예제 #1
0
ArrayGrid<double>* WienerDeconvolve::EstimateIdealSpectrum( FFTBand* pFFTInputGrid, FFTBand* pFFTPSFGrid, double noiseLevel )
{
   int width  = pFFTInputGrid->GetWidth();
   int height = pFFTInputGrid->GetHeight();
   bool needInitialisation = true;
   double initialRealValue = 0.0;
   ArrayGrid<double>* pEstimatedIdealSpectrum = new ArrayGrid<double>( width, height, needInitialisation, initialRealValue );
   double fourierNoiseLevel = width * height * noiseLevel * noiseLevel;
   
   for (int y = 0; y < height; y++)
   {
      for (int x = 0; x < width; x++)
      {
         double spectrumDegraded = std::norm( pFFTInputGrid->GetValue( x, y ) );  // norm is square of magnitude
         double spectrumPsf      = std::norm(   pFFTPSFGrid->GetValue( x, y ) ); // norm is square of magnitude
         double estimatedValue = THRESHOLD;
         double differenceValue = spectrumDegraded - fourierNoiseLevel;
         if (( spectrumPsf > THRESHOLD) && (differenceValue > 0.0 ))
         {
            estimatedValue = differenceValue / spectrumPsf;
         }
         pEstimatedIdealSpectrum->SetValue( x, y, estimatedValue );
      }
   }
   
   ArrayGrid<double>* pSmoothSpectrum = GaussConvolve::ConvolveSeparable(pEstimatedIdealSpectrum, 1.5);
   delete pEstimatedIdealSpectrum;
   return pSmoothSpectrum;
}
예제 #2
0
image::ArrayGrid<int>* MedianFilter::RunMedian( image::ArrayGrid<int>* pGridIn, int mySize)
{
   int windowWidth = 2 * mySize + 1;
   int windowArea  = windowWidth * windowWidth;
   int medianPosition = (int)(windowArea / 2);

   int width  = pGridIn->GetWidth();
   int height = pGridIn->GetHeight();

   int *pR = new int [windowArea];

   ArrayGrid<int>* pGridOut = pGridIn->Clone();

   for (int y = mySize; y < height - mySize; y++)
   {
      for (int x = mySize; x < width - mySize; x ++)
      {
         int myIndex=0;
         for (int s = -mySize; s <= mySize; s++)
         {
            for (int t = -mySize; t <= mySize; t++)
            {
               pR[myIndex] = pGridIn->GetValue( x+s, y+t );
               myIndex++;
            }
         }
         qsort( pR, windowArea, sizeof(int), MathUtils::CompareIntegers );
         pGridOut->SetValue( x, y, pR[ medianPosition ] );
      }
   }

   delete [] pR;
   return pGridOut;
}
void PyramidKeyPointDetector::AccumulateScales( )
{
   int nrScalesToAccumulate = mvEnergyMaps.size();

   int width   = mvEnergyMaps[0]->GetWidth();
   int height  = mvEnergyMaps[0]->GetHeight();
   bool needsInitialisation = true;
   double initialValue = 0.0;
   ArrayGrid<double>* pAccumulate = new ArrayGrid<double>( width, height, needsInitialisation, initialValue );
   for (int y = 0; y < height; y++)
   {
      for (int x = 0; x < width; x++)
      {
         double tmpValue = 0.0;
         for (int scale = 0; scale < nrScalesToAccumulate; scale++)
         {
            tmpValue += mvEnergyMaps[scale]->GetValue(x, y);
         }
         pAccumulate->SetValue(x, y, tmpValue);
      }
   }
   mvAccumulatedMaps.push_back( pAccumulate );

   int scaleID = nrScalesToAccumulate;
   stringstream ss;
   ss << "AccumulatedEnergy-" << scaleID << ".pgm";
   ImageIO::WritePGM( pAccumulate, ss.str(), ImageIO::NORMAL_OUT );

   ArrayGrid<bool>* pKeyPointsMap  = FindLocalMaxima( pAccumulate );
   stringstream ss1;
   ss1 << "KeyPointMap-" << scaleID << ".pgm";
   ImageIO::WritePGM( pKeyPointsMap, ss1.str() );
}
image::ArrayGrid<bool>* PyramidKeyPointDetector::FindLocalMaxima( ArrayGrid<double>* pGrid )
{
   int size = 5;
   int width   = pGrid->GetWidth();
   int height  = pGrid->GetHeight();
   bool needsInitialisation = true;
   double initialValue = false;
   ArrayGrid<bool>* pKeyPointsMap = new ArrayGrid<bool>( width, height, needsInitialisation, initialValue );
   pKeyPointsMap->SetGridValues( false );
   for (int y = size; y < height-size; y++)
   {
      for (int x = size; x < width-size; x++)
      {
         bool isLocalMaximum = true;
         for (int dy = -size; dy <= size; dy++)
         {
            for (int dx = -size; dx <= size; dx++)
            {
               if (  (dx != 0) || (dy != 0) )
               {
                  if (pGrid->GetValue(x+dx, y+dy) >= pGrid->GetValue(x, y))
                  {
                     isLocalMaximum = false;
                  }
               }
            }
         }
         pKeyPointsMap->SetValue(x, y, isLocalMaximum);
      }
   }
   return pKeyPointsMap;
}
예제 #5
0
void PyramidDenoiser::DenoiseLevelWiener(int level)
{
   if ( level < (int)( mpPyramid->GetNumberOfScales() - 1 ) )
   {
      PyramidLevel<double>* pBandSet;
      if (level != -1)
      {
         pBandSet = mpPyramid->GetRecursiveScale(level);
      }
      else
      {
         pBandSet = mpPyramid->GetResidualScale();
      }

      for (int orientationIndex = 0; orientationIndex < pBandSet->GetNumberOfOrientations(); orientationIndex++)
      {
         ArrayGrid<double>* pBand = pBandSet->GetOrientedBand( orientationIndex);
         for (int y = 0; y < pBand->GetHeight(); y++)
         {
            for (int x = 0; x < pBand->GetWidth(); x++)
            {
               double sigmaSignal = EstimateSigmaSignal( pBand, x, y, mSigmaNoise, mWindowSize );
               double shrinkageFactor = ComputeWienerShrinkagefactor( sigmaSignal, mSigmaNoise );
               pBand->SetValue( x, y, shrinkageFactor * pBand->GetValue( x, y ) );
            }
         }
      }
   }
   else
   {
      std::cerr << "PyramidDenoiser::DenoiseLevelWiener: Cannot denoise level " << level << " since top level is " << mpPyramid->GetNumberOfScales() << std::endl << std::flush;
   }
}
예제 #6
0
void PyramidDenoiser::DenoiseLevelBivariate(int level)
{
   if (level < (int)(mpPyramid->GetNumberOfScales() - 1))
   {
      PyramidLevel<double>* pBandSetCurrent;
      PyramidLevel<double>* pBandSetParent;
      if (level != -1)
      {
         pBandSetCurrent = mpPyramid->GetRecursiveScale(level);
         pBandSetParent = mpPyramid->GetRecursiveScale(level+1);
      }
      else
      {
         pBandSetCurrent = mpPyramid->GetResidualScale();
         pBandSetParent = mpPyramid->GetRecursiveScale(0);
      }

      double avgVariance = 0.0;

      double scaleNoiseVariance = mSigmaNoise / GetScaledNoiseVarianceFactor( level );
      double scaleParentChildFactor = GetScaledParentChildFactor( level);

      for (int orientationIndex = 0; orientationIndex < pBandSetCurrent->GetNumberOfOrientations(); orientationIndex++)
      {
         ArrayGrid<double>* pBandCurrent = pBandSetCurrent->GetOrientedBand( orientationIndex);
         ArrayGrid<double>* pBandParent = pBandSetParent->GetOrientedBand( orientationIndex);

         double meanVal     = GridStatistics<double>::GetGridMean( pBandCurrent );
         double varianceVal = GridStatistics<double>::GetGridVariance( pBandCurrent, meanVal );

         #ifdef DEBUG
         cout << "Denoising level " << level << " and orientationIndex " << orientationIndex
              << ", variance is " << varianceVal << " and scaled noise variance = " << scaleNoiseVariance << endl << flush;
         #endif
         avgVariance += varianceVal;


         for (int y = 0; y < pBandCurrent->GetHeight(); y++)
         {
            for (int x = 0; x < pBandCurrent->GetWidth(); x++)
            {
               double sigmaSignal = EstimateSigmaSignal( pBandCurrent, x, y, mSigmaNoise, mWindowSize );
               double w1 = pBandCurrent->GetValue(x,y);
               double w2 = pBandParent->GetValue(x/2,y/2) / scaleParentChildFactor;
               double shrinkageFactor = ComputeBivariateShrinkagefactor(w1, w2, sigmaSignal, scaleNoiseVariance );
               pBandCurrent->SetValue(x,y, shrinkageFactor * w1);
            }
         }
      }
      #ifdef DEBUG
      cout << "Average variance at scale level = " << (avgVariance) / (double)(pBandSetCurrent->GetNumberOfOrientations())
           << endl << flush;
      #endif
   }
   else
   {
      std::cerr << "PyramidDenoiser::DenoiseLevelBivariate: Cannot denoise level " << level << " since top level is " << mpPyramid->GetNumberOfScales() << std::endl << std::flush;
   }
}
bool PyramidKeyPointDetector::MergeOrientations1( int scale )
{
   ArrayGrid<double>* pEnergyMap = 0;
   ArrayGrid<double>* pUpscaledEnergyMap = 0;

   PyramidLevel< std::complex< double > >* pPyrLevel = 0;

   if (scale >= 0)
   {
      pPyrLevel = mpPyramid->GetRecursiveScale( scale );
   }
   else
   {
      pPyrLevel = mpPyramid->GetResidualScale( );
   }
   int width = pPyrLevel->GetWidth();
   int height = pPyrLevel->GetHeight();
   bool needsInitialisation = true;
   double initialValue = 0.0;
   pEnergyMap = new ArrayGrid<double>( width, height, needsInitialisation, initialValue );

   int nrOrientations = mpPyramid->GetNumberOfOrientations();

   for (int y = 0; y < height; y++)
   {
      for (int x = 0; x < width; x++)
      {
         double tmpValue = 0.0;
         for (int i = 0; i < nrOrientations-1; i++)
         {
            for (int j = i+1; j < nrOrientations; j++)
            {
               if (  ( abs( i - j ) > 1 ) && ( abs( i - j%(nrOrientations-1) ) > 0) )
               {
                  tmpValue += (    abs( pPyrLevel->GetOrientedBand( i )->GetValue(x, y) )
                                 * abs( pPyrLevel->GetOrientedBand( j )->GetValue(x, y) )
                              );
               }
            }
         }
         pEnergyMap->SetValue( x, y, tmpValue);
      }
   }

   if (scale > 0)
   {
      pUpscaledEnergyMap = GaussConvolve::UpsampleGaussianInterpolated( pEnergyMap, MathUtils::ComputeIntegerPower(2, scale ) );
      delete pEnergyMap;
   }
   else
   {
      pUpscaledEnergyMap = pEnergyMap;
   }
   mvEnergyMaps.push_back( pUpscaledEnergyMap );

   return true;
}
bool CriticallySubsampledTransform::Reconstruct( double threshold )
{
   ArrayGrid<double>* pRecursiveInput = mpPyramid->GetLowpassResidual( );
   for ( mCurrentScale = mNrScales-1; mCurrentScale >= 0; mCurrentScale-- )
   {
      int width  = pRecursiveInput->GetWidth();
      int height = pRecursiveInput->GetHeight();
      int upScaledWidth  =  width * 2;
      int upScaledHeight = height * 2;
      bool needsInitialisation = true;
      double initialValue = 0.0;

      ArrayGrid<double>* pLLGrid = new ArrayGrid<double>( upScaledWidth, upScaledHeight, needsInitialisation, initialValue );
      for (int y = 0; y < upScaledHeight; y+=2)
      {
         for (int x = 0; x < upScaledWidth; x+=2)
         {
            int halfX = x/2;
            int halfY = y/2;

            double x00 = pRecursiveInput->GetValue( halfX, halfY );
            
            double x01 = mpPyramid->GetRecursiveScale( mCurrentScale )->GetOrientedBand( 0 )->GetValue( halfX, halfY );
            double x10 = mpPyramid->GetRecursiveScale( mCurrentScale )->GetOrientedBand( 1 )->GetValue( halfX, halfY );
            double x11 = mpPyramid->GetRecursiveScale( mCurrentScale )->GetOrientedBand( 2 )->GetValue( halfX, halfY );
            
            pLLGrid->SetValue( x  , y  , (x00 + x01 + x10 + x11) / 2.0 );
            pLLGrid->SetValue( x  , y+1, (x00 + x01 - x10 - x11) / 2.0 );
            pLLGrid->SetValue( x+1, y  , (x00 - x01 + x10 - x11) / 2.0 );
            pLLGrid->SetValue( x+1, y+1, (x00 - x01 - x10 + x11) / 2.0 );
         }
      }
      pRecursiveInput = pLLGrid->Clone(); delete pLLGrid;
   }
   mpDecomposeReconstructGrid = pRecursiveInput;
   return true;
}
예제 #9
0
ArrayGrid<double>* DistanceTransform::Run( ArrayGrid<double> *pGridIn)
{
   int width = pGridIn->GetWidth();
   int height = pGridIn->GetHeight();

   ArrayGrid<double> *pGridOut = new ArrayGrid<double>(width, height, false, 0.0);
   for (int y = 0; y < height; y++)
   {
      for (int x = 0; x < width; x++)
      {
         if (pGridIn->GetValue(x, y) > 245 )  // objects of interest to compute distance to
         {
            pGridOut->SetValue(x, y, 0);
         }
         else                                 // image background
         {
            pGridOut->SetValue( x, y, STIRA_INFINITE);
         }
      }
   }

   DistanceTransform2D( pGridOut );
   return pGridOut;
}
예제 #10
0
bool TestEmptyPlusGaussianNoise( int width, int height, double intensity, double sigma )
{
   ArrayGrid<double>* pGrid = new ArrayGrid<double>( width, height );
   Random rn;

   for (int y = 0; y < height; y++)
   {
      for (int x = 0; x < width; x++)
      {
         pGrid->SetValue(x, y, (intensity + rn.normal( 0.0, sigma )) );
      }
   }

   double testMean     = GridStatistics<double>::GetGridMean( pGrid );
   double testVariance = GridStatistics<double>::GetGridVariance( pGrid, testMean );
   double testKurtosis = GridStatistics<double>::GetGridKurtosis( pGrid, testMean, testVariance );

   if ( fabs( sqrt( testVariance ) - sigma ) > 0.1 )
   {
      cout << "mean intensity: theoretically = " << intensity << "\t estimated = " << testMean << " too different!!" << endl << flush;
      delete pGrid;
      return false;
   }

   if ( fabs( intensity - testMean ) > 0.1 )
   {
      cout << "variance: theoretically = " << sigma * sigma << " \t estimated = " << testVariance << " too different!!" << endl << flush;
      delete pGrid;
      return false;
   }

   if ( fabs( testKurtosis ) > 0.1 )
   {
      cout << "Kurtosis  " << testKurtosis << " too large (should be close to 0 for Gaussian noise)!!" << endl << flush;
      delete pGrid;
      return false;
   }

   cout << "Mean     : theoretically = " << intensity     << " \t estimated = " << testMean     << " \t -> OK!" << endl << flush;
   cout << "variance : theoretically = " << sigma * sigma << " \t estimated = " << testVariance << " \t -> OK!" << endl << flush;
   cout << "Kurtosis : " << testKurtosis << ", is close to 0 \t\t\t -> OK!" << endl << flush;

   delete pGrid;
   return true;
}
예제 #11
0
void TestDrawFigure()
{
   int width = 512;
   int height = 512;
   ArrayGrid<int>* pGrid = new ArrayGrid<int>( width, height );
   std::vector< Point<int> > vCorners;
   Point<int> p1(129, 52);   vCorners.push_back( p1 );
   Point<int> p2(234, 32);   vCorners.push_back( p2 );
   Point<int> p3(356, 51);   vCorners.push_back( p3 );
   Point<int> p4(267, 248);  vCorners.push_back( p4 );
   Point<int> p5(100, 156);  vCorners.push_back( p5 );

   pGrid->SetValue( DrawFigures::DrawPolygon( vCorners ), 250 );

   Point<int> testPointOut( 60, 240 );
   pGrid->SetValue( testPointOut.GetX(), testPointOut.GetY(), 250 );
   pGrid->SetValue( testPointOut.GetX()-1, testPointOut.GetY(), 250 );
   pGrid->SetValue( testPointOut.GetX()+1, testPointOut.GetY(), 250 );
   pGrid->SetValue( testPointOut.GetX(), testPointOut.GetY()-1, 250 );
   pGrid->SetValue( testPointOut.GetX(), testPointOut.GetY()+1, 250 );

   ImageIO::WritePGM( pGrid, std::string("Polygon.pgm"), ImageIO::NULL_OUT );

   bool testRes1 = DrawFigures::IsPointInPolygon( vCorners, testPointOut );
   cout << "Test point 1 in polygon = " << testRes1 << endl << flush;

   Point<int> testPointIn( 226, 126 );
   pGrid->SetValue( testPointIn.GetX(), testPointIn.GetY(), 250 );
   pGrid->SetValue( testPointIn.GetX()-1, testPointIn.GetY(), 250 );
   pGrid->SetValue( testPointIn.GetX()+1, testPointIn.GetY(), 250 );
   pGrid->SetValue( testPointIn.GetX(), testPointIn.GetY()-1, 250 );
   pGrid->SetValue( testPointIn.GetX(), testPointIn.GetY()+1, 250 );

   ImageIO::WritePGM( pGrid, std::string("Polygon.pgm"), ImageIO::NULL_OUT );

   bool testRes2 = DrawFigures::IsPointInPolygon( vCorners, testPointIn );
   cout << "Test point 2 in polygon = " << testRes2 << endl << flush;
   delete pGrid;
}
예제 #12
0
image::ArrayGrid<double>* MedianFilter::RunMedian( image::ArrayGrid<double>* pGridIn, int size)
{
   int windowWidth = 2 * size + 1;
   int windowArea  = windowWidth * windowWidth;
   int medianPosition = (int)(windowArea / 2);

   int width = pGridIn->GetWidth();
   int height = pGridIn->GetHeight();

   double* pR = new double[windowArea];

   ArrayGrid<double>* pGridOut = pGridIn->Clone();
   //cout << "Input grid has width " << pGridIn->GetWidth() << " and height " << pGridIn->GetHeight() << endl;

   for (int y = size; y < height-size; y++)
   {
      for (int x = size; x < width - size; x ++)
      {
         int index=0;
         for (int s = -size; s <= size; s++)
         {
            for (int t = -size; t <= size; t++)
            {
               pR[index] = pGridIn->GetValue( x+s, y+t );
               index++;
            }
         }
         qsort( pR, windowArea, sizeof(double), MathUtils::CompareDoubles );
         pGridOut->SetValue( x, y, pR[medianPosition] );
      }
   }

   delete [] pR;
   cout << "Output grid has width " << pGridOut->GetWidth() << " and height " << pGridOut-> GetHeight() << endl;
   return pGridOut;
}
예제 #13
0
image::ArrayGrid<double>* MedianFilter::RunHybridMedian( image::ArrayGrid<double>* pGridIn, int size)
{
   int kernelSize = 4 * size + 1;
   int medianPosition = (int)(kernelSize / 2);

   int width = pGridIn->GetWidth();
   int height = pGridIn->GetHeight();

   double *pPlusShaped = new double [kernelSize];
   double *pXShaped = new double [kernelSize];
   double medianOfMedians[3], centralPixelValue;

   ArrayGrid<double>* pGridOut = pGridIn->Clone();

   for (int y = size; y < height - size; y++)
   {
      for (int x = size; x < width - size; x ++)
      {
         centralPixelValue = pGridIn->GetValue( x, y );
         int index = 0;
         for (int s = -size; s <= size; s++)
         {
            if (s != 0)
            {
               pPlusShaped[index] = pGridIn->GetValue( x + s, y );
               index++;
            }
         }
         for (int s = -size; s <= size; s++)
         {
            if (s != 0)
            {
               pPlusShaped[ index ] = pGridIn->GetValue( x, y + s );
               index++;
            }
         }
         pPlusShaped[ index ] = centralPixelValue ;

         index = 0;
         for (int s = -size; s <= size; s++)
         {
            if (s != 0)
            {
               pXShaped[ index ] = pGridIn->GetValue( x + s, y + s );
               index++;
            }
         }
         for (int s = -size; s <= size; s++)
         {
            if (s != 0)
            {
               pXShaped[ index ] = pGridIn->GetValue( x + s, y - s );
               index ++;
            }
         }
         pXShaped[ index ] = centralPixelValue;

         qsort( pPlusShaped, kernelSize, sizeof(double), MathUtils::CompareDoubles );
         qsort( pXShaped,    kernelSize, sizeof(double), MathUtils::CompareDoubles );

         medianOfMedians[ 0 ] = pPlusShaped[ medianPosition ];
         medianOfMedians[ 1 ] = pXShaped[ medianPosition ];
         medianOfMedians[ 2 ] = centralPixelValue;

         qsort( medianOfMedians, 3, sizeof(double), MathUtils::CompareDoubles );

         pGridOut->SetValue( x, y, medianOfMedians[1] );
      }
   }
   delete []pPlusShaped;
   delete []pXShaped;
   return pGridOut;
}
예제 #14
0
ArrayGrid<bool>* StegerLineDetector::Run( ArrayGrid<double>* pGridIn, double sigmaSmooth, double lowerThreshold, double higherThreshold, bool isModeLight )
{
   int width = pGridIn->GetWidth();
   int height = pGridIn->GetHeight();
   OrientationGrid* pOrientationGrid = new OrientationGrid(width, height);  // NOT initialized at construction; values are set below
   ArrayGrid<bool>* pLineGrid = new ArrayGrid<bool>(width, height);  // NOT initialized at construction; values are set below
   pLineGrid->SetGridValues( false );
   
   ArrayGrid<double>* pGx  = GaussConvolve::DerivativeConvolveFFT( pGridIn, sigmaSmooth, sigmaSmooth, GaussConvolve::DERIVATIVE_X  );
   ArrayGrid<double>* pGy  = GaussConvolve::DerivativeConvolveFFT( pGridIn, sigmaSmooth, sigmaSmooth, GaussConvolve::DERIVATIVE_Y  );
   ArrayGrid<double>* pGxx = GaussConvolve::DerivativeConvolveFFT( pGridIn, sigmaSmooth, sigmaSmooth, GaussConvolve::DERIVATIVE_XX );
   ArrayGrid<double>* pGyy = GaussConvolve::DerivativeConvolveFFT( pGridIn, sigmaSmooth, sigmaSmooth, GaussConvolve::DERIVATIVE_YY );
   ArrayGrid<double>* pGxy = GaussConvolve::DerivativeConvolveFFT( pGridIn, sigmaSmooth, sigmaSmooth, GaussConvolve::DERIVATIVE_XY );
   
   for (int y = 0; y < height; y++)
   {
      for (int x = 0; x < width; x++)
      {
         double eigenValue1, eigenValue2, eigenValue;
         common::Point<double> eigenVector1;
         common::Point<double> eigenVector2;
         
         EigenValueComputation( pGxx->GetValue(x, y), pGyy->GetValue(x, y), pGxy->GetValue(x, y),
                                eigenValue1, eigenValue2, eigenVector1, eigenVector2);

         if (isModeLight == true)
         {
            eigenValue = -eigenValue1;
         }
         else
         {
            eigenValue = eigenValue1;
         }
         
         if (eigenValue > 0.0)
         {
            double n1 = eigenVector1.x;
            double n2 = eigenVector1.y;
            
            double a = pGxx->GetValue(x, y) * n1 * n1 + 2.0 * pGxy->GetValue(x, y) * n1 * n2 + pGyy->GetValue(x, y) * n2 * n2;
            double b = pGx->GetValue(x, y) * n1 + pGy->GetValue(x, y) * n2;
            double linearSolution;
            if ( MathUtils::SolveLinearEquation( a, b, linearSolution ) == true )
            {
               double p1 = linearSolution * n1;
               double p2 = linearSolution * n2;
               if ((fabs (p1) <= EDGE_THRESHOLD) && (fabs (p2) <= EDGE_THRESHOLD))
               {
                  int xx = (int)(x + p1 + 0.5);
                  int yy = (int)(y + p2 + 0.5);
                  if (  (xx >= 0) && (xx < width) && (yy >=0) && (yy < height))
                  {
                     if (eigenValue >= lowerThreshold)
                     {
                        if (eigenValue >= higherThreshold)
                        {
                           pLineGrid->SetValue(xx, yy, true);
                        }
                     }
                     else
                     {
                        pLineGrid->SetValue(xx, yy, false);
                     }
                  }
               }
            }
            
            pOrientationGrid->SetAngle( x, y, MathUtils::ComputeArgument( eigenVector1.x,  eigenVector1.y ) );
            pOrientationGrid->SetMagnitude( x, y, eigenValue1);
         }
      }
   }
   //pOrientationGrid->ExportMagnitudeImage( string("StegerMagnitude.pgm") );
   //pOrientationGrid->ExportOrientationImage( string("StegerOrientation.pgm"), -100000.0 );
   
   delete pGx;
   delete pGy;
   delete pGxx;
   delete pGyy;
   delete pGxy;
   delete pOrientationGrid;
   return pLineGrid;
}
bool CriticallySubsampledTransform::Decompose( image::ArrayGrid<double>* pSourceGrid, int nrScales )
{
   Initialize( pSourceGrid, nrScales );
   
   ArrayGrid<double>* pRecursiveInput = pSourceGrid;

   for ( mCurrentScale = 0; mCurrentScale < mNrScales; mCurrentScale++)
   {
      int width  = pRecursiveInput->GetWidth();
      int height = pRecursiveInput->GetHeight();
      int downScaledWidth  = width / 2;
      int downScaledHeight = height / 2;
      bool needsInitialisation = true;
      double initialValue = 0.0;
      ArrayGrid<double>* pLLGrid = new ArrayGrid<double>( downScaledWidth, downScaledHeight, needsInitialisation, initialValue );
      ArrayGrid<double>* pLHGrid = new ArrayGrid<double>( downScaledWidth, downScaledHeight, needsInitialisation, initialValue );
      ArrayGrid<double>* pHLGrid = new ArrayGrid<double>( downScaledWidth, downScaledHeight, needsInitialisation, initialValue );
      ArrayGrid<double>* pHHGrid = new ArrayGrid<double>( downScaledWidth, downScaledHeight, needsInitialisation, initialValue );
            
      // to be sure that (x+1) and (y+1) won't exceed width and height
      int limitWidth  = (width  / 2 ) * 2;
      int limitHeight = (height / 2 ) * 2;
      
      #ifdef DEBUG
      cout << "Width = " << width << ", height = " << height << endl << flush;
      cout << "limitWidth = " << limitWidth << ", limitHeight = " << limitHeight << endl << flush;
      #endif
      
      for (int y = 0; y < limitHeight; y+=2)
      {
         for (int x = 0; x < limitWidth; x+=2)
         {
            int halfX = x/2;
            int halfY = y/2;
            
            #ifdef DEBUG
            //cout << "Width = " << width << ", height = " << height << endl << flush;
            if ((x+1) > width)  {cout <<  (x+1) << " goes out of bounds." << endl << flush;}
            if ((y+1) > height) {cout <<  (y+1) << " goes out of bounds." << endl << flush;}
            assert ((x+1) < width);
            assert ((y+1) < height);
            #endif
            
            double x00 = pRecursiveInput->GetValue( x,   y   );
            double x01 = pRecursiveInput->GetValue( x,   y+1 );
            double x10 = pRecursiveInput->GetValue( x+1, y   );
            double x11 = pRecursiveInput->GetValue( x+1, y+1 );
            
            pLLGrid->SetValue( halfX, halfY, ( (x00 + x01 + x10 + x11) / 2.0) );
            pLHGrid->SetValue( halfX, halfY, ( (x00 + x01 - x10 - x11) / 2.0) );
            pHLGrid->SetValue( halfX, halfY, ( (x00 - x01 + x10 - x11) / 2.0) );
            pHHGrid->SetValue( halfX, halfY, ( (x00 - x01 - x10 + x11) / 2.0) );
         }
      }
      mpPyramid->GetRecursiveScale( mCurrentScale )->AddOrientedBand( pLHGrid );   // in on index 0
      mpPyramid->GetRecursiveScale( mCurrentScale )->AddOrientedBand( pHLGrid );   // in on index 1
      mpPyramid->GetRecursiveScale( mCurrentScale )->AddOrientedBand( pHHGrid );   // in on index 2

      mpPyramid->SetLowpassResidual( pLLGrid );
      
      pRecursiveInput = mpPyramid->GetLowpassResidual( );
   }
   return true;
}