From 746ccac0e7f1260a65b3b36c4822402ac443ad2a Mon Sep 17 00:00:00 2001 From: Guillaume Pasero <guillaume.pasero@c-s.fr> Date: Thu, 15 Mar 2012 18:37:47 +0100 Subject: [PATCH] ENH: in PixelWiseBlockMatching : add basic subp-pixel interpolation --- .../otbPixelWiseBlockMatching.cxx | 18 ++ .../otbPixelWiseBlockMatchingImageFilter.h | 32 ++- .../otbPixelWiseBlockMatchingImageFilter.txx | 240 ++++++++++++++++++ 3 files changed, 283 insertions(+), 7 deletions(-) diff --git a/Applications/DisparityMap/otbPixelWiseBlockMatching.cxx b/Applications/DisparityMap/otbPixelWiseBlockMatching.cxx index 3a9f47c965..3328caa8cd 100644 --- a/Applications/DisparityMap/otbPixelWiseBlockMatching.cxx +++ b/Applications/DisparityMap/otbPixelWiseBlockMatching.cxx @@ -187,6 +187,9 @@ private: AddParameter(ParameterType_Int,"bm.maxvd","Maximum vertical disparity"); SetParameterDescription("bm.maxvd","Maximum vertical disparity to explore (can be negative)"); + AddParameter(ParameterType_Empty,"bm.subpixel","Do sub-pixel interpolation"); + SetParameterDescription("bm.subpixel", "Estimate disparities with sub-pixel precision"); + AddParameter(ParameterType_Choice, "bm.initdisp", "Initial disparities"); AddChoice("bm.initdisp.none", "None"); SetParameterDescription("bm.initdisp.none", "No initial disparity used"); @@ -379,6 +382,11 @@ private: m_SSDBlockMatcher->SetMaximumHorizontalDisparity(maxhdisp); m_SSDBlockMatcher->SetMinimumVerticalDisparity(minvdisp); m_SSDBlockMatcher->SetMaximumVerticalDisparity(maxvdisp); + if (IsParameterEnabled("bm.subpixel")) + { + m_SSDBlockMatcher->DoSubPixelInterpolationOn(); + } + AddProcess(m_SSDBlockMatcher,"SSD block matching"); if(masking) { @@ -418,6 +426,11 @@ private: m_NCCBlockMatcher->SetMinimumVerticalDisparity(minvdisp); m_NCCBlockMatcher->SetMaximumVerticalDisparity(maxvdisp); m_NCCBlockMatcher->MinimizeOff(); + if (IsParameterEnabled("bm.subpixel")) + { + m_NCCBlockMatcher->DoSubPixelInterpolationOn(); + } + AddProcess(m_NCCBlockMatcher,"NCC block matching"); if(masking) @@ -458,6 +471,11 @@ private: m_LPBlockMatcher->SetMaximumHorizontalDisparity(maxhdisp); m_LPBlockMatcher->SetMinimumVerticalDisparity(minvdisp); m_LPBlockMatcher->SetMaximumVerticalDisparity(maxvdisp); + if (IsParameterEnabled("bm.subpixel")) + { + m_LPBlockMatcher->DoSubPixelInterpolationOn(); + } + AddProcess(m_LPBlockMatcher,"Lp block matching"); if(masking) diff --git a/Code/DisparityMap/otbPixelWiseBlockMatchingImageFilter.h b/Code/DisparityMap/otbPixelWiseBlockMatchingImageFilter.h index 01ef8f1bb8..e12a245d1b 100644 --- a/Code/DisparityMap/otbPixelWiseBlockMatchingImageFilter.h +++ b/Code/DisparityMap/otbPixelWiseBlockMatchingImageFilter.h @@ -21,6 +21,8 @@ #include "itkImageToImageFilter.h" #include "itkConstNeighborhoodIterator.h" +#include "itkImageRegionConstIterator.h" +#include "itkImageRegionIterator.h" #include "otbImage.h" namespace otb @@ -41,11 +43,11 @@ template <class TInputImage, class TOutputMetricImage> ITK_EXPORT class SSDBlockMatching { public: - typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeigghborhoodIteratorType; + typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeighborhoodIteratorType; typedef typename TOutputMetricImage::ValueType MetricValueType; // Implement the SSD operator - inline MetricValueType operator()(ConstNeigghborhoodIteratorType & a, ConstNeigghborhoodIteratorType & b) const + inline MetricValueType operator()(ConstNeighborhoodIteratorType & a, ConstNeighborhoodIteratorType & b) const { MetricValueType ssd = 0; @@ -71,11 +73,11 @@ template <class TInputImage, class TOutputMetricImage> ITK_EXPORT class NCCBlockMatching { public: - typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeigghborhoodIteratorType; + typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeighborhoodIteratorType; typedef typename TOutputMetricImage::ValueType MetricValueType; // Implement the NCC operator - inline MetricValueType operator()(ConstNeigghborhoodIteratorType & a, ConstNeigghborhoodIteratorType & b) const + inline MetricValueType operator()(ConstNeighborhoodIteratorType & a, ConstNeighborhoodIteratorType & b) const { MetricValueType meanA(0),meanB(0), sigmaA(0), sigmaB(0), cov(0), ncc(0); @@ -129,10 +131,10 @@ template <class TInputImage, class TOutputMetricImage> ITK_EXPORT class LPBlockMatching { public: - typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeigghborhoodIteratorType; + typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeighborhoodIteratorType; typedef typename TOutputMetricImage::ValueType MetricValueType; - LPBlockMatching(): m_P(0) + LPBlockMatching(): m_P(1) { } @@ -149,7 +151,7 @@ public: } // Implement the Lp metric - inline MetricValueType operator()(ConstNeigghborhoodIteratorType & a, ConstNeigghborhoodIteratorType & b) const + inline MetricValueType operator()(ConstNeighborhoodIteratorType & a, ConstNeighborhoodIteratorType & b) const { MetricValueType score(0); @@ -244,6 +246,10 @@ public: typedef typename InputImageType::SizeType SizeType; typedef typename InputImageType::IndexType IndexType; typedef typename InputImageType::RegionType RegionType; + + typedef typename TOutputMetricImage::ValueType MetricValueType; + + typedef itk::ConstNeighborhoodIterator<TInputImage> ConstNeighborhoodIteratorType; /** Set left input */ void SetLeftInput( const TInputImage * image); @@ -339,6 +345,10 @@ public: /** Get the initial disparity fields */ const TOutputDisparityImage * GetHorizontalDisparityInput() const; const TOutputDisparityImage * GetVerticalDisparityInput() const; + + itkSetMacro(DoSubPixelInterpolation, bool); + itkGetConstReferenceMacro(DoSubPixelInterpolation,bool); + itkBooleanMacro(DoSubPixelInterpolation); protected: /** Constructor */ @@ -360,6 +370,11 @@ private: PixelWiseBlockMatchingImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemeFnted + bool InterpolateSubPixelPosition(ConstNeighborhoodIteratorType & leftPatch, + itk::ImageRegionIterator<OutputDisparityImageType> & hDispIt, + itk::ImageRegionIterator<OutputDisparityImageType> & vDispIt, + itk::ImageRegionIterator<OutputMetricImageType> & metricIt); + /** The radius of the blocks */ SizeType m_Radius; @@ -389,6 +404,9 @@ private: /** Initial vertical disparity (0 by default, used if an exploration radius is set) */ int m_InitVerticalDisparity; + + /** flag to perform sub-pixel interpolation */ + bool m_DoSubPixelInterpolation; }; } // end namespace otb diff --git a/Code/DisparityMap/otbPixelWiseBlockMatchingImageFilter.txx b/Code/DisparityMap/otbPixelWiseBlockMatchingImageFilter.txx index e6762a991e..3d215380c3 100644 --- a/Code/DisparityMap/otbPixelWiseBlockMatchingImageFilter.txx +++ b/Code/DisparityMap/otbPixelWiseBlockMatchingImageFilter.txx @@ -60,6 +60,8 @@ TOutputDisparityImage,TMaskImage,TBlockMatchingFunctor> // Default exploration radius : 0 (not used) m_ExplorationRadius.Fill(0); + + m_DoSubPixelInterpolation = false; } @@ -675,7 +677,245 @@ TOutputDisparityImage,TMaskImage,TBlockMatchingFunctor> } } + + // subpixel interpolation case + if (m_DoSubPixelInterpolation) + { + itk::ConstNeighborhoodIterator<TInputImage> leftIt(m_Radius,inLeftPtr,outputRegionForThread); + itk::ImageRegionIterator<TOutputDisparityImage> outHDispIt(outHDispPtr,outputRegionForThread); + itk::ImageRegionIterator<TOutputDisparityImage> outVDispIt(outVDispPtr,outputRegionForThread); + itk::ImageRegionIterator<TOutputMetricImage> outMetricIt(outMetricPtr,outputRegionForThread); + + itk::ConstantBoundaryCondition<TInputImage> nbc1; + leftIt.OverrideBoundaryCondition(&nbc1); + + leftIt.GoToBegin(); + outHDispIt.GoToBegin(); + outVDispIt.GoToBegin(); + outMetricIt.GoToBegin(); + + while (!leftIt.IsAtEnd() + || !outHDispIt.IsAtEnd() + || !outVDispIt.IsAtEnd() + || !outMetricIt.IsAtEnd()) + { + bool isInterpolated = InterpolateSubPixelPosition(leftIt,outHDispIt,outVDispIt,outMetricIt); + + ++leftIt; + ++outHDispIt; + ++outVDispIt; + ++outMetricIt; + } + + } + +} + +template <class TInputImage, class TOutputMetricImage, +class TOutputDisparityImage, class TMaskImage, class TBlockMatchingFunctor> +bool +PixelWiseBlockMatchingImageFilter<TInputImage,TOutputMetricImage, +TOutputDisparityImage,TMaskImage,TBlockMatchingFunctor> +::InterpolateSubPixelPosition(ConstNeighborhoodIteratorType & leftPatch, + itk::ImageRegionIterator<OutputDisparityImageType> & hDispIt, + itk::ImageRegionIterator<OutputDisparityImageType> & vDispIt, + itk::ImageRegionIterator<OutputMetricImageType> & metricIt) +{ + IndexType curLeftPos = leftPatch.GetIndex(); + SizeType curRadius = leftPatch.GetRadius(); + + const TInputImage * inRightPtr = this->GetRightInput(); + RegionType rightLargestRegion = inRightPtr->GetLargestPossibleRegion(); + + float hDisp_f = static_cast<float>(hDispIt.Get()); + float vDisp_f = static_cast<float>(vDispIt.Get()); + + int hDisp_i = static_cast<int>(vcl_floor(hDisp_f + 0.5)); + int vDisp_i = static_cast<int>(vcl_floor(vDisp_f + 0.5)); + + IndexType curRightPos(curLeftPos); + curRightPos[0]+=hDisp_i; + curRightPos[1]+=vDisp_i; + + // check if the current right position is inside the right image + if (!rightLargestRegion.IsInside(curRightPos)) + { + return false; + } + + // compute metric around current right position + bool horizontalInterpolation = false; + bool verticalInterpolation = false; + + // metrics for neighbors positions, sorted like this : + // [up,up-right,right,down-right,down,down-left,left,up-left] + double neighborsMetric[8] = {0,0,0,0,0,0,0,0}; + int firstNeighbor = 0; + int stepNeighbor = 4; + + RegionType smallRightRegion; + smallRightRegion.SetIndex(0,curRightPos[0]-1); + smallRightRegion.SetIndex(1,curRightPos[1]-1); + smallRightRegion.SetSize(0,3); + smallRightRegion.SetSize(1,3); + + itk::ConstNeighborhoodIterator<TInputImage> rightIt(curRadius,inRightPtr,smallRightRegion); + + if (m_MinimumVerticalDisparity < vDisp_i && vDisp_i < m_MaximumVerticalDisparity) + { + IndexType upIndex(curRightPos); + upIndex[1]+= (-1); + IndexType downIndex(curRightPos); + downIndex[1]+= 1; + if ( rightLargestRegion.IsInside(upIndex) && rightLargestRegion.IsInside(downIndex) ) + { + verticalInterpolation = true; + + rightIt.SetLocation(upIndex); + neighborsMetric[0] = m_Functor(leftPatch,rightIt); + + rightIt.SetLocation(downIndex); + neighborsMetric[4] = m_Functor(leftPatch,rightIt); + + } + } + + if (m_MinimumHorizontalDisparity < hDisp_i && hDisp_i < m_MaximumHorizontalDisparity) + { + IndexType leftIndex(curRightPos); + leftIndex[0]+= (-1); + IndexType rightIndex(curRightPos); + rightIndex[0]+= 1; + if ( rightLargestRegion.IsInside(leftIndex) && rightLargestRegion.IsInside(rightIndex) ) + { + horizontalInterpolation = true; + firstNeighbor = 2; + + rightIt.SetLocation(rightIndex); + neighborsMetric[2] = m_Functor(leftPatch,rightIt); + + rightIt.SetLocation(leftIndex); + neighborsMetric[6] = m_Functor(leftPatch,rightIt); + + } + } + + if ( !verticalInterpolation && !horizontalInterpolation) + { + return false; + } + + // if both vertical and horizontal interpolation, compute metrics on corners + if (verticalInterpolation && horizontalInterpolation) + { + firstNeighbor = 0; + stepNeighbor = 1; + + IndexType uprightIndex(curRightPos); + uprightIndex[0]+= 1; + uprightIndex[1]+= (-1); + rightIt.SetLocation(uprightIndex); + neighborsMetric[1] = m_Functor(leftPatch,rightIt); + + IndexType downrightIndex(curRightPos); + downrightIndex[0]+= 1; + downrightIndex[1]+= 1; + rightIt.SetLocation(downrightIndex); + neighborsMetric[3] = m_Functor(leftPatch,rightIt); + + IndexType downleftIndex(curRightPos); + downleftIndex[0]+= (-1); + downleftIndex[1]+= 1; + rightIt.SetLocation(downleftIndex); + neighborsMetric[5] = m_Functor(leftPatch,rightIt); + + IndexType upleftIndex(curRightPos); + upleftIndex[0]+= (-1); + upleftIndex[1]+= (-1); + rightIt.SetLocation(upleftIndex); + neighborsMetric[7] = m_Functor(leftPatch,rightIt); + } + + // check if the position is a minimum (or maximum if !m_Minimize) + double curMetric = metricIt.Get(); + for (unsigned int i=firstNeighbor; i<8 ; i+=stepNeighbor) + { + if (m_Minimize) + { + if (curMetric > neighborsMetric[i]) + { + return false; + } + } + else + { + if (curMetric < neighborsMetric[i]) + { + return false; + } + } + } + + + // Interpolate position : parabola fit + if (verticalInterpolation && !horizontalInterpolation) + { + //vertical only + double deltaV = 0.5 - (1.0 / (1.0 + (neighborsMetric[0]-curMetric) / (neighborsMetric[4]-curMetric))); + if (deltaV > (-0.5) && deltaV < 0.5) + { + vDispIt.Set( static_cast<double>(vDisp_i) + deltaV); + } + else + { + return false; + } + } + else if (!verticalInterpolation && horizontalInterpolation) + { + // horizontal only + double deltaH = 0.5 - (1.0 / (1.0 + (neighborsMetric[6]-curMetric) / (neighborsMetric[2]-curMetric))); + if (deltaH > (-0.5) && deltaH < 0.5) + { + hDispIt.Set( static_cast<double>(hDisp_i) + deltaH); + } + else + { + return false; + } + } + else + { + //both horizontal and vertical + double dx = 0.5 * (neighborsMetric[2] - neighborsMetric[6]); + double dy = 0.5 * (neighborsMetric[4] - neighborsMetric[0]); + double dxx = neighborsMetric[2] + neighborsMetric[6] - 2.0 * curMetric; + double dyy = neighborsMetric[4] + neighborsMetric[0] - 2.0 * curMetric; + double dxy = 0.25 * (neighborsMetric[3] + neighborsMetric[7] - neighborsMetric[1] - neighborsMetric[5]); + double det = dxx*dyy - dxy*dxy; + if (vcl_abs(det) < (1e-10)) + { + return false; + } + else + { + double deltaH = (-dx * dyy + dy * dxy )/det; + double deltaV = ( dx * dxy - dy * dxx )/det; + if (deltaH > (-1.0) && deltaH < 1.0 && deltaV > (-1.0) && deltaV < 1.0) + { + hDispIt.Set( static_cast<double>(hDisp_i) + deltaH); + vDispIt.Set( static_cast<double>(vDisp_i) + deltaV); + } + else + { + return false; + } + } + } + + return true; } + } // End namespace otb #endif -- GitLab