diff --git a/Code/DisparityMap/otbDisparityMapToDEMFilter.h b/Code/DisparityMap/otbDisparityMapToDEMFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..45d44e19e0c7b0b58cf13b79f934da2d9154ec25 --- /dev/null +++ b/Code/DisparityMap/otbDisparityMapToDEMFilter.h @@ -0,0 +1,198 @@ +/*========================================================================= + + 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 __otbDisparityMapToDEMFilter_h +#define __otbDisparityMapToDEMFilter_h + +#include "itkImageToImageFilter.h" +#include "otbGenericRSTransform.h" +// #include "itkConstNeighborhoodIterator.h" +// #include "itkImageRegionConstIterator.h" +// #include "itkImageRegionIterator.h" +// #include "otbImage.h" + +namespace otb +{ + +/** \class DisparityMapToDEMFilter + * \brief Project an input disparity map into a regular DEM + * + * This filter uses an input disparity map (horizontal and vertical) to produce a DEM with a regular sampling + * in the chosen map projection system. The elevation is computed from the triangulation of the "left-right" pairs + * of pixels matched. When several elevations are possible on a DEM cell, the highest is kept. + * + * The inputs are: + * - the horizontal and vertical disparity maps (SetHorizontalDisparityMapInput, SetVerticalDisparityMapInput) + * - the original image pair (in sensor geometry) (SetLeftInput, SetRightInput) + * - the deformation grids of the epipolar geometry (SetLeftEpipolarGridInput, SetRightEpipolarGridInput) + * - the mask associated to the input disparity maps (SetDisparityMaskInput) + * [- the DEM map projection system] + * + * The outputs are: + * - the DEM (GetDEMOutput) + * + * \sa FineRegistrationImageFilter + * \sa StereorectificationDeformationFieldSource + * \sa SubPixelDisparityImageFilter + * \sa PixelWiseBlockMatchingImageFilter + * + * \ingroup Streamed + * \ingroup Threaded + * + */ +template <class TDisparityImage, class TInputImage, class TOutputDEMImage = TDisparityImage, + class TEpipolarGridImage = TDisparityImage, class TMaskImage = otb::Image<unsigned char> > +class ITK_EXPORT DisparityMapToDEMFilter : + public itk::ImageToImageFilter<TDisparityImage,TOutputDEMImage> +{ +public: + /** Standard class typedef */ + typedef DisparityMapToDEMFilter Self; + typedef itk::ImageToImageFilter<TDisparityImage, + TOutputDEMImage> 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(DisparityMapToDEMFilter, ImageToImageFilter); + + /** Usefull typedefs */ + typedef TDisparityImage DisparityMapType; + typedef TInputImage SensorImageType; + typedef TOutputDEMImage DEMImageType; + typedef TEpipolarGridImage GridImageType; + typedef TMaskImage MaskImageType; + + typedef typename DEMImageType::RegionType RegionType; + + // 3D RS transform + // TODO: Allow to tune precision (i.e. double or float) + typedef otb::GenericRSTransform<double,3,3> RSTransformType; + //typedef typename RSTransformType::Pointer RSTransformPointerType; + + // 3D points + typedef typename RSTransformType::InputPointType TDPointType; + + /** Set horizontal disparity map input */ + void SetHorizontalDisparityMapInput( const TDisparityImage * hmap); + + /** Set vertical disparity map input */ + void SetVerticalDisparityMapInput( const TDisparityImage * vmap); + + /** Set left input */ + void SetLeftInput( const TInputImage * image); + + /** Set right input */ + void SetRightInput( const TInputImage * image); + + /** Set left epipolar grid (deformation grid from sensor image to epipolar space, regular in epipolar space)*/ + void SetLeftEpipolarGridInput( const TEpipolarGridImage * grid); + + /** Set right epipolar grid (deformation grid from sensor image to epipolar space, regular in epipolar space)*/ + void SetRightEpipolarGridInput( const TEpipolarGridImage * grid); + + /** Set mask associated to disparity maps (optional, pixels with a null mask value are ignored) */ + void SetDisparityMaskInput( const TMaskImage * mask); + + /** Get the inputs */ + const TDisparityImage * GetHorizontalDisparityMapInput() const; + const TDisparityImage * GetVerticalDisparityMapInput() const; + const TInputImage * GetLeftInput() const; + const TInputImage * GetRightInput() const; + const TEpipolarGridImage * GetLeftEpipolarGridInput() const; + const TEpipolarGridImage * GetRightEpipolarGridInput() const; + const TMaskImage * GetDisparityMaskInput() const; + + /** Get DEM output*/ + const TOutputDEMImage * GetDEMOutput() const; + TOutputDEMImage * GetDEMOutput(); + + /** Set/Get macro for minimum elevation */ + itkSetMacro(ElevationMin, double); + itkGetConstReferenceMacro(ElevationMin, double); + + /** Set/Get macro for maximum elevation */ + itkSetMacro(ElevationMax, double); + itkGetConstReferenceMacro(ElevationMax, double); + + /** Set/Get macro for DEM grid step */ + itkSetMacro(DEMGridStep, double); + itkGetConstReferenceMacro(DEMGridStep, double); + + /** Get/Set the average elevation */ + itkSetMacro(AverageElevation,double); + itkGetConstReferenceMacro(AverageElevation,double); + + /** Get/Set the DEM directory */ + itkSetStringMacro(DEMDirectory); + itkGetStringMacro(DEMDirectory); + + /** Get/Set the geoid file */ + itkSetStringMacro(GeoidFile); + itkGetStringMacro(GeoidFile); + +protected: + /** Constructor */ + DisparityMapToDEMFilter(); + + /** Destructor */ + virtual ~DisparityMapToDEMFilter(); + + /** Generate output information */ + virtual void GenerateOutputInformation(); + + /** Generate input requrested region */ + virtual void GenerateInputRequestedRegion(); + + /** Before threaded generate data */ + virtual void BeforeThreadedGenerateData(); + + /** Threaded generate data */ + virtual void ThreadedGenerateData(const RegionType & outputRegionForThread, int threadId); + +private: + DisparityMapToDEMFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + /** Minimum elevation of the DEM in meters (over the chosen reference : DEM, geoid, average)*/ + double m_ElevationMin; + + /** Maximum elevation of the DEM in meters (over the chosen reference : DEM, geoid, average)*/ + double m_ElevationMax; + + /** DEM grid step (in meters) */ + double m_DEMGridStep; + + /** DEM Directory */ + std::string m_DEMDirectory; + + /** Geoid File */ + std::string m_GeoidFile; + + /** Average Elevation */ + double m_AverageElevation; +}; +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbDisparityMapToDEMFilter.txx" +#endif + +#endif diff --git a/Code/DisparityMap/otbDisparityMapToDEMFilter.txx b/Code/DisparityMap/otbDisparityMapToDEMFilter.txx new file mode 100644 index 0000000000000000000000000000000000000000..378a186bd972fb37aed147aa44d1c4bbd5b89925 --- /dev/null +++ b/Code/DisparityMap/otbDisparityMapToDEMFilter.txx @@ -0,0 +1,626 @@ +/*========================================================================= + + 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 __otbDisparityMapToDEMFilter_txx +#define __otbDisparityMapToDEMFilter_txx + +#include "otbDisparityMapToDEMFilter.h" +// #include "itkImageRegionConstIterator.h" +// #include "itkImageRegionIterator.h" +// #include "itkProgressReporter.h" +// #include "itkConstantBoundaryCondition.h" + +namespace otb +{ + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::DisparityMapToDEMFilter() +{ + // Set the number of inputs + this->SetNumberOfInputs(7); + this->SetNumberOfRequiredInputs(1); + + // Set the outputs + this->SetNumberOfOutputs(1); + this->SetNthOutput(0,TOutputDEMImage::New()); + + // Default DEM reconstruction parameters + m_ElevationMin = 0.0; + m_ElevationMax = 100.0; + m_DEMGridStep = 10.0; + + m_AverageElevation = 0; + m_DEMDirectory = ""; + m_GeoidFile = ""; +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::~DisparityMapToDEMFilter() +{} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +void +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::SetHorizontalDisparityMapInput( const TDisparityImage * hmap) +{ + // Process object is not const-correct so the const casting is required. + this->SetNthInput(0, const_cast<TDisparityImage *>( hmap )); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +void +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::SetVerticalDisparityMapInput( const TDisparityImage * vmap) +{ + // Process object is not const-correct so the const casting is required. + this->SetNthInput(1, const_cast<TDisparityImage *>( vmap )); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +void +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::SetLeftInput( const TInputImage * image) +{ + // Process object is not const-correct so the const casting is required. + this->SetNthInput(2, const_cast<TInputImage *>( image )); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +void +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::SetRightInput( const TInputImage * image) +{ + // Process object is not const-correct so the const casting is required. + this->SetNthInput(3, const_cast<TInputImage *>( image )); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +void +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::SetLeftEpipolarGridInput( const TEpipolarGridImage * grid) +{ + // Process object is not const-correct so the const casting is required. + this->SetNthInput(4, const_cast<TEpipolarGridImage *>( grid )); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +void +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::SetRightEpipolarGridInput( const TEpipolarGridImage * grid) +{ + // Process object is not const-correct so the const casting is required. + this->SetNthInput(5, const_cast<TEpipolarGridImage *>( grid )); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +void +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::SetDisparityMaskInput( const TMaskImage * mask) +{ + // Process object is not const-correct so the const casting is required. + this->SetNthInput(6, const_cast<TMaskImage *>( mask )); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +const TDisparityImage * +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::GetHorizontalDisparityMapInput() const +{ + if(this->GetNumberOfInputs()<1) + { + return 0; + } + return static_cast<const TDisparityImage *>(this->itk::ProcessObject::GetInput(0)); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +const TDisparityImage * +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::GetVerticalDisparityMapInput() const +{ + if(this->GetNumberOfInputs()<2) + { + return 0; + } + return static_cast<const TDisparityImage *>(this->itk::ProcessObject::GetInput(1)); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +const TInputImage * +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::GetLeftInput() const +{ + if(this->GetNumberOfInputs()<3) + { + return 0; + } + return static_cast<const TInputImage *>(this->itk::ProcessObject::GetInput(2)); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +const TInputImage * +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::GetRightInput() const +{ + if(this->GetNumberOfInputs()<4) + { + return 0; + } + return static_cast<const TInputImage *>(this->itk::ProcessObject::GetInput(3)); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +const TEpipolarGridImage * +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::GetLeftEpipolarGridInput() const +{ + if(this->GetNumberOfInputs()<5) + { + return 0; + } + return static_cast<const TEpipolarGridImage *>(this->itk::ProcessObject::GetInput(4)); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +const TEpipolarGridImage * +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::GetRightEpipolarGridInput() const +{ + if(this->GetNumberOfInputs()<6) + { + return 0; + } + return static_cast<const TEpipolarGridImage *>(this->itk::ProcessObject::GetInput(5)); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +const TMaskImage * +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::GetDisparityMaskInput() const +{ + if(this->GetNumberOfInputs()<7) + { + return 0; + } + return static_cast<const TMaskImage *>(this->itk::ProcessObject::GetInput(6)); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +const TOutputDEMImage * +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::GetDEMOutput() const +{ + if(this->GetNumberOfOutputs()<1) + { + return 0; + } + return static_cast<const TOutputDEMImage *>(this->itk::ProcessObject::GetOutput(0)); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +TOutputDEMImage * +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::GetDEMOutput() +{ + if(this->GetNumberOfOutputs()<1) + { + return 0; + } + return static_cast<TOutputDEMImage *>(this->itk::ProcessObject::GetOutput(0)); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +void +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::GenerateOutputInformation() +{ + // Get common area between images + const TInputImage * leftImgPtr = this->GetLeftInput(); + const TInputImage * rightImgPtr = this->GetRightInput(); + TOutputDEMImage * outputPtr = this->GetDEMOutput(); + + // Setup the DEM handler if needed + typename DEMHandler::Pointer demHandler = DEMHandler::New(); + + bool useDEM = false; + + // Set-up a transform to use the DEMHandler + typedef otb::GenericRSTransform<> RSTransform2DType; + RSTransform2DType::Pointer leftToGroundTransform = RSTransform2DType::New(); + leftToGroundTransform->SetInputKeywordList(leftImgPtr->GetImageKeywordlist()); + if(m_DEMDirectory!="") + { + demHandler->OpenDEMDirectory(m_DEMDirectory); + leftToGroundTransform->SetDEMDirectory(m_DEMDirectory); + useDEM = true; + } + if(m_GeoidFile!="") + { + leftToGroundTransform->SetGeoidFile(m_GeoidFile); + demHandler->OpenGeoidFile(m_GeoidFile); + } + leftToGroundTransform->InstanciateTransform(); + + RSTransform2DType::Pointer rightToGroundTransform = RSTransform2DType::New(); + rightToGroundTransform->SetInputKeywordList(rightImgPtr->GetImageKeywordlist()); + if(m_DEMDirectory!="") + { + demHandler->OpenDEMDirectory(m_DEMDirectory); + rightToGroundTransform->SetDEMDirectory(m_DEMDirectory); + useDEM = true; + } + if(m_GeoidFile!="") + { + rightToGroundTransform->SetGeoidFile(m_GeoidFile); + demHandler->OpenGeoidFile(m_GeoidFile); + } + rightToGroundTransform->InstanciateTransform(); + + // left image + typename SensorImageType::SizeType inputSize = leftImgPtr->GetLargestPossibleRegion().GetSize(); + typename SensorImageType::PointType tmpPoint; + tmpPoint = leftImgPtr->GetOrigin(); + RSTransform2DType::OutputPointType left_ul = leftToGroundTransform->TransformPoint(tmpPoint); + + tmpPoint[0] = (leftImgPtr->GetOrigin())[0] + (leftImgPtr->GetSpacing())[0] * static_cast<double>(inputSize[0]); + tmpPoint[1] = (leftImgPtr->GetOrigin())[1]; + RSTransform2DType::OutputPointType left_ur = leftToGroundTransform->TransformPoint(tmpPoint); + + tmpPoint[0] = (leftImgPtr->GetOrigin())[0] + (leftImgPtr->GetSpacing())[0] * static_cast<double>(inputSize[0]); + tmpPoint[1] = (leftImgPtr->GetOrigin())[1] + (leftImgPtr->GetSpacing())[1] * static_cast<double>(inputSize[1]); + RSTransform2DType::OutputPointType left_lr = leftToGroundTransform->TransformPoint(tmpPoint); + + tmpPoint[0] = (leftImgPtr->GetOrigin())[0]; + tmpPoint[1] = (leftImgPtr->GetOrigin())[1] + (leftImgPtr->GetSpacing())[1] * static_cast<double>(inputSize[1]); + RSTransform2DType::OutputPointType left_ll = leftToGroundTransform->TransformPoint(tmpPoint); + + // right image + inputSize = rightImgPtr->GetLargestPossibleRegion().GetSize(); + tmpPoint = rightImgPtr->GetOrigin(); + RSTransform2DType::OutputPointType right_ul = rightToGroundTransform->TransformPoint(tmpPoint); + + tmpPoint[0] = (rightImgPtr->GetOrigin())[0] + (rightImgPtr->GetSpacing())[0] * static_cast<double>(inputSize[0]); + tmpPoint[1] = (rightImgPtr->GetOrigin())[1]; + RSTransform2DType::OutputPointType right_ur = rightToGroundTransform->TransformPoint(tmpPoint); + + tmpPoint[0] = (rightImgPtr->GetOrigin())[0] + (rightImgPtr->GetSpacing())[0] * static_cast<double>(inputSize[0]); + tmpPoint[1] = (rightImgPtr->GetOrigin())[1] + (rightImgPtr->GetSpacing())[1] * static_cast<double>(inputSize[1]); + RSTransform2DType::OutputPointType right_lr = rightToGroundTransform->TransformPoint(tmpPoint); + + tmpPoint[0] = (rightImgPtr->GetOrigin())[0]; + tmpPoint[1] = (rightImgPtr->GetOrigin())[1] + (rightImgPtr->GetSpacing())[1] * static_cast<double>(inputSize[1]); + RSTransform2DType::OutputPointType right_ll = rightToGroundTransform->TransformPoint(tmpPoint); + + + double left_xmin = std::min(std::min(std::min(left_ul[0],left_ur[0]),left_lr[0]),left_ll[0]); + double left_xmax = std::max(std::max(std::max(left_ul[0],left_ur[0]),left_lr[0]),left_ll[0]); + double left_ymin = std::min(std::min(std::min(left_ul[1],left_ur[1]),left_lr[1]),left_ll[1]); + double left_ymax = std::max(std::max(std::max(left_ul[1],left_ur[1]),left_lr[1]),left_ll[1]); + + double right_xmin = std::min(std::min(std::min(right_ul[0],right_ur[0]),right_lr[0]),right_ll[0]); + double right_xmax = std::max(std::max(std::max(right_ul[0],right_ur[0]),right_lr[0]),right_ll[0]); + double right_ymin = std::min(std::min(std::min(right_ul[1],right_ur[1]),right_lr[1]),right_ll[1]); + double right_ymax = std::max(std::max(std::max(right_ul[1],right_ur[1]),right_lr[1]),right_ll[1]); + + double box_xmin = std::max(left_xmin,right_xmin); + double box_xmax = std::min(left_xmax,right_xmax); + double box_ymin = std::max(left_ymin,right_ymin); + double box_ymax = std::min(left_ymax,right_ymax); + + if (box_xmin >= box_xmax || box_ymin >= box_ymax) + { + itkExceptionMacro(<<"Wrong reconstruction area, images don't overlap, check image corners"); + } + + // Choose origin + typename TOutputDEMImage::PointType outOrigin; + outOrigin[0] = box_xmin; + outOrigin[1] = box_ymin; + outputPtr->SetOrigin(outOrigin); + + // Choose step + typename TOutputDEMImage::SpacingType outSpacing; + outSpacing[0] = m_DEMGridStep; + outSpacing[1] = m_DEMGridStep; + + // Compute output size + typename DEMImageType::RegionType outRegion; + outRegion.SetIndex(0,0); + outRegion.SetIndex(1,0); + outRegion.SetSize(0, static_cast<unsigned int>((box_xmax - box_xmin) / m_DEMGridStep)); + outRegion.SetSize(1, static_cast<unsigned int>((box_ymax - box_ymin) / m_DEMGridStep)); + + outputPtr->SetLargestPossibleRegion(outRegion); + outputPtr->SetNumberOfComponentsPerPixel(1); +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +void +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::GenerateInputRequestedRegion() +{ + // For the epi grid : generate full buffer + TEpipolarGridImage * leftGrid = const_cast<TEpipolarGridImage*>(this->GetLeftEpipolarGridInput()); + TEpipolarGridImage * rightGrid = const_cast<TEpipolarGridImage*>(this->GetRightEpipolarGridInput()); + + leftGrid->SetRequestedRegionToLargestPossibleRegion(); + rightGrid->SetRequestedRegionToLargestPossibleRegion(); + + leftGrid->UpdateOutputData(); + rightGrid->UpdateOutputData(); + + // For the input left-right images + // -> No need, only use metadata and keywordlist + const TInputImage * leftSensor = this->GetLeftInput(); + TOutputDEMImage * outputDEM = this->GetDEMOutput(); + + typename DEMImageType::RegionType outRegion = outputDEM->GetRequestedRegion(); + typename DEMImageType::PointType outOrigin = outputDEM->GetOrigin(); + typename DEMImageType::SpacingType outSpacing = outputDEM->GetSpacing(); + + RSTransformType::Pointer groundToLeftTransform = RSTransformType::New(); + if(m_DEMDirectory!="") + { + groundToLeftTransform->SetDEMDirectory(m_DEMDirectory); + } + if(m_GeoidFile!="") + { + groundToLeftTransform->SetGeoidFile(m_GeoidFile); + } + groundToLeftTransform->SetOutputKeywordList(leftSensor->GetImageKeywordlist()); + groundToLeftTransform->InstanciateTransform(); + + // For the disparity maps and mask + // Iterate over OutputRequestedRegion corners for elevation min and max + // up left at elevation min + TDisparityImage * horizDisp = const_cast<TDisparityImage*>(this->GetHorizontalDisparityMapInput()); + TDisparityImage * vertiDisp = const_cast<TDisparityImage*>(this->GetVerticalDisparityMapInput()); + TMaskImage * maskDisp = const_cast<TMaskImage*>(this->GetDisparityMaskInput()); + + // We impose that both disparity map inputs have the same size + if(horizDisp->GetLargestPossibleRegion() + != vertiDisp->GetLargestPossibleRegion()) + { + itkExceptionMacro(<<"Horizontal and vertical disparity maps do not have the same size ! Horizontal largest region: " + <<horizDisp->GetLargestPossibleRegion()<<", vertical largest region: "<<vertiDisp->GetLargestPossibleRegion()); + } + + if (maskDisp && horizDisp->GetLargestPossibleRegion() != maskDisp->GetLargestPossibleRegion()) + { + itkExceptionMacro(<<"Disparity map and mask do not have the same size ! Map region : " + <<horizDisp->GetLargestPossibleRegion()<<", mask region : "<<maskDisp->GetLargestPossibleRegion()); + } + + + TDPointType corners[8]; + corners[0][0]= outOrigin[0] + outSpacing[0] * outRegion.GetIndex(0); + corners[0][1]= outOrigin[1] + outSpacing[1] * outRegion.GetIndex(1); + corners[0][2]= m_ElevationMin; + // up left at elevation max + corners[1][0]= corners[0][0]; + corners[1][1]= corners[0][1]; + corners[1][2]= m_ElevationMax; + // up right at elevation min + corners[2][0]= outOrigin[0] + outSpacing[0] * (outRegion.GetIndex(0) + outRegion.GetSize(0)); + corners[2][1]= outOrigin[1] + outSpacing[1] * outRegion.GetIndex(1); + corners[2][2]= m_ElevationMin; + // up right at elevation max + corners[3][0]= corners[2][0]; + corners[3][1]= corners[2][1]; + corners[3][2]= m_ElevationMax; + // low right at elevation min + corners[4][0]= outOrigin[0] + outSpacing[0] * (outRegion.GetIndex(0) + outRegion.GetSize(0)); + corners[4][1]= outOrigin[1] + outSpacing[1] * (outRegion.GetIndex(1) + outRegion.GetSize(1)); + corners[4][2]= m_ElevationMin; + // low right at elevation max + corners[5][0]= corners[4][0]; + corners[5][1]= corners[4][1]; + corners[5][2]= m_ElevationMax; + // low left at elevation min + corners[6][0]= outOrigin[0] + outSpacing[0] * outRegion.GetIndex(0); + corners[6][1]= outOrigin[1] + outSpacing[1] * (outRegion.GetIndex(1) + outRegion.GetSize(1)); + corners[6][2]= m_ElevationMin; + // low left at elevation max + corners[7][0]= corners[6][0]; + corners[7][1]= corners[6][1]; + corners[7][2]= m_ElevationMax; + + double x_loc,y_loc; + double a_grid,b_grid; + double u_loc[2]; + double v_loc[2]; + double det; + typename GridImageType::IndexType gridIndex; + typename GridImageType::IndexType gridIndexU; + typename GridImageType::IndexType gridIndexV; + typename GridImageType::PixelType origLoc(2); + typename GridImageType::PixelType uUnitLoc(2); + typename GridImageType::PixelType vUnitLoc(2); + + typename GridImageType::RegionType gridRegion = leftGrid->GetLargestPossibleRegion(); + itk::ContinuousIndex<double,2> gridContiIndex; + typename DisparityMapType::PointType epiPosition; + itk::ContinuousIndex<double,2> epiContiIndex; + double epiIndexMin[2]; + double epiIndexMax[2]; + int maxGridIndex[2]; + int minGridIndex[2]; + maxGridIndex[0] = static_cast<int>(gridRegion.GetIndex(0) + gridRegion.GetSize(0)) - 2; + maxGridIndex[1] = static_cast<int>(gridRegion.GetIndex(1) + gridRegion.GetSize(1)) - 2; + minGridIndex[0] = static_cast<int>(gridRegion.GetIndex(0)); + minGridIndex[1] = static_cast<int>(gridRegion.GetIndex(1)); + + for (unsigned int k=0 ; k<8 ; k++) + { + // compute left image coordinate + TDPointType tmpSensor = groundToLeftTransform->TransformPoint(corners[k]); + + // compute epipolar position + gridIndex[0] = minGridIndex[0]; + gridIndex[1] = minGridIndex[1]; + + //we assume 3 iterations are enough to find the 4 surrounding pixels + for (unsigned int s=0 ; s<2 ; s++) + { + gridIndexU[0] = gridIndex[0] + 1; + gridIndexU[1] = gridIndex[1]; + + gridIndexV[0] = gridIndex[0]; + gridIndexV[1] = gridIndex[1] + 1; + + origLoc = leftGrid->GetPixel(gridIndex); + uUnitLoc = leftGrid->GetPixel(gridIndexU); + vUnitLoc = leftGrid->GetPixel(gridIndexV); + + u_loc[0] = static_cast<double>(uUnitLoc[0] - origLoc[0]); + u_loc[1] = static_cast<double>(uUnitLoc[1] - origLoc[1]); + + v_loc[0] = static_cast<double>(vUnitLoc[0] - origLoc[0]); + v_loc[1] = static_cast<double>(vUnitLoc[1] - origLoc[1]); + + det = u_loc[0] * v_loc[1] - v_loc[0] * u_loc[1]; + + x_loc = static_cast<double>(tmpSensor[0]) - static_cast<double>(origLoc[0]); + y_loc = static_cast<double>(tmpSensor[1]) - static_cast<double>(origLoc[1]); + + a_grid = (x_loc * v_loc[1] - y_loc * v_loc[0]) / det; + b_grid = (y_loc * u_loc[0] - x_loc * u_loc[1]) / det; + + gridContiIndex[0] = static_cast<double>(gridIndex[0]) + a_grid; + gridContiIndex[1] = static_cast<double>(gridIndex[1]) + b_grid; + + leftGrid->TransformContinuousIndexToPhysicalPoint(gridContiIndex, epiPosition); + + horizDisp->TransformPhysicalPointToContinuousIndex(epiPosition,epiContiIndex); + + if (0.0 < a_grid && a_grid < 1.0 && 0.0 < b_grid && b_grid < 1.0) + { + // The four nearest positions in epipolar grid have been found : stop search + break; + } + else + { + // Shift the gridIndex + int a_grid_int = static_cast<int>(gridIndex[0]) + static_cast<int>(vcl_floor(a_grid)); + int b_grid_int = static_cast<int>(gridIndex[1]) + static_cast<int>(vcl_floor(b_grid)); + + if (a_grid_int < minGridIndex[0]) a_grid_int = minGridIndex[0]; + if (a_grid_int > maxGridIndex[0]) a_grid_int = maxGridIndex[0]; + if (b_grid_int < minGridIndex[1]) b_grid_int = minGridIndex[1]; + if (b_grid_int > maxGridIndex[1]) b_grid_int = maxGridIndex[1]; + + gridIndex[0] = a_grid_int; + gridIndex[1] = b_grid_int; + } + } + + if (k==0) + { + epiIndexMin[0] = epiContiIndex[0]; + epiIndexMin[1] = epiContiIndex[1]; + epiIndexMax[0] = epiContiIndex[0]; + epiIndexMax[1] = epiContiIndex[1]; + } + else + { + if (epiContiIndex[0] < epiIndexMin[0]) epiIndexMin[0] = epiContiIndex[0]; + if (epiContiIndex[1] < epiIndexMin[1]) epiIndexMin[1] = epiContiIndex[1]; + if (epiIndexMax[0] < epiContiIndex[0]) epiIndexMax[0] = epiContiIndex[0]; + if (epiIndexMax[1] < epiContiIndex[1]) epiIndexMax[1] = epiContiIndex[1]; + } + } + + typename DisparityMapType::RegionType inputDisparityRegion; + inputDisparityRegion.SetIndex(0, static_cast<int>(vcl_floor(epiIndexMin[0]))); + inputDisparityRegion.SetIndex(1, static_cast<int>(vcl_floor(epiIndexMin[1]))); + inputDisparityRegion.SetSize(0, 1 + static_cast<unsigned int>(vcl_floor(epiIndexMax[0] - epiIndexMin[0] + 0.5))); + inputDisparityRegion.SetSize(1, 1 + static_cast<unsigned int>(vcl_floor(epiIndexMax[1] - epiIndexMin[1] + 0.5))); + + // crop the disparity region at the largest possible region + if ( inputDisparityRegion.Crop(horizDisp->GetLargestPossibleRegion())) + { + horizDisp->SetRequestedRegion( inputDisparityRegion ); + vertiDisp->SetRequestedRegion( inputDisparityRegion ); + + if (maskDisp) + { + maskDisp->SetRequestedRegion( inputDisparityRegion ); + } + } + else + { + // Couldn't crop the region (requested region is outside the largest + // possible region). Throw an exception. + // store what we tried to request (prior to trying to crop) + horizDisp->SetRequestedRegion( inputDisparityRegion ); + vertiDisp->SetRequestedRegion( inputDisparityRegion ); + + // build an exception + itk::InvalidRequestedRegionError e(__FILE__, __LINE__); + std::ostringstream msg; + msg << this->GetNameOfClass() + << "::GenerateInputRequestedRegion()"; + e.SetLocation(msg.str().c_str()); + e.SetDescription("Requested region is (at least partially) outside the largest possible region of disparity map."); + e.SetDataObject(horizDisp); + throw e; + } +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +void +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::BeforeThreadedGenerateData() +{ + // TODO +} + +template <class TDisparityImage, class TInputImage, class TOutputDEMImage, +class TEpipolarGridImage, class TMaskImage> +void +DisparityMapToDEMFilter<TDisparityImage,TInputImage,TOutputDEMImage,TEpipolarGridImage,TMaskImage> +::ThreadedGenerateData(const RegionType & outputRegionForThread, int threadId) +{ + // TODO +} + +} + +#endif