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; }
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; }
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; } }
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; }
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; }
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; }
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; }
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; }
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; }
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; }