/** * @file tmo_fattal02.cpp * @brief TMO: Gradient Domain High Dynamic Range Compression * * Implementation of Gradient Domain High Dynamic Range Compression * by Raanan Fattal, Dani Lischinski, Michael Werman. * * @author Grzegorz Krawczyk, * * * This file is a part of PFSTMO package. * ---------------------------------------------------------------------- * Copyright (C) 2003,2004 Grzegorz Krawczyk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ---------------------------------------------------------------------- * * $Id: tmo_fattal02.cpp,v 1.1 2007/06/14 15:27:46 gkrawczyk Exp $ */ #include #include #include #include #include #include #include "pde.h" #include using namespace std; //!! TODO: for debugging purposes // #define PFSEOL "\x0a" // static void dumpPFS( const char *fileName, const pfs::Array2D *data, const char *channelName ) // { // FILE *fh = fopen( fileName, "wb" ); // assert( fh != NULL ); // int width = data->getCols(); // int height = data->getRows(); // fprintf( fh, "PFS1" PFSEOL "%d %d" PFSEOL "1" PFSEOL "0" PFSEOL // "%s" PFSEOL "0" PFSEOL "ENDH", width, height, channelName ); // for( int y = 0; y < height; y++ ) // for( int x = 0; x < width; x++ ) { // fwrite( &((*data)(x,y)), sizeof( float ), 1, fh ); // } // fclose( fh ); // } //-------------------------------------------------------------------- void downSample(pfs::Array2D* A, pfs::Array2D* B) { int width = B->getCols(); int height = B->getRows(); int x,y; for( y=0 ; ygetCols(); int height = I->getRows(); int size = width*height; int x,y; pfs::Array2D* T = new pfs::Array2DImpl(width,height); //--- X blur for( y=0 ; ygetCols(); int height = H->getRows(); int size = width*height; pyramids[0] = new pfs::Array2DImpl(width,height); for( int i=0 ; igetCols(); int height = H->getRows(); float divider = pow( 2.0f, k+1 ); float avgGrad = 0.0f; for( int y=0 ; ygetCols(); int height = B->getRows(); int awidth = A->getCols(); int aheight = A->getRows(); int x,y; for( y=0 ; ygetCols(); // int height = A->getRows(); // int x,y; // for( y=0 ; ygetCols(); int height = gradients[nlevels-1]->getRows(); int k; pfs::Array2D** fi = new pfs::Array2D*[nlevels]; fi[nlevels-1] = new pfs::Array2DImpl(width,height); for( k=0 ; k=0 ; k-- ) { width = gradients[k]->getCols(); height = gradients[k]->getRows(); for( int y=0 ; y1e-4 ) value = a/(grad+noise) * pow((grad+noise)/a, beta); (*fi[k])(x,y) *= value; } // create next level if( k>1 ) { width = gradients[k-1]->getCols(); height = gradients[k-1]->getRows(); fi[k-1] = new pfs::Array2DImpl(width,height); } else fi[0] = FI; // highest level -> result if( k>0 ) { upSample(fi[k], fi[k-1]); // upsample to next level gaussianBlur(fi[k-1],fi[k-1]); } } for( k=1 ; kgetRows() * I->getCols(); std::vector vI; for( int i=0 ; igetCols(); // +2 for boundaries int height = Y->getRows(); int size = width*height; int x,y,i,k; // find max & min values, normalize to range 0..100 and take logarithm float minLum = (*Y)(0,0); float maxLum = (*Y)(0,0); for( i=0 ; imaxLum ) ? (*Y)(i) : maxLum; } pfs::Array2D* H = new pfs::Array2DImpl(width, height); for( i=0 ; i=MSIZE ) { nlevels++; mins /= 2; } pfs::Array2D** pyramids = new pfs::Array2D*[nlevels]; createGaussianPyramids(H, pyramids, nlevels); // calculate gradients and its average values on pyramid levels pfs::Array2D** gradients = new pfs::Array2D*[nlevels]; float* avgGrad = new float[nlevels]; for( k=0 ; kgetCols(), pyramids[k]->getRows()); avgGrad[k] = calculateGradients(pyramids[k],gradients[k], k); } // calculate fi matrix pfs::Array2D* FI = new pfs::Array2DImpl(width, height); calculateFiMatrix(FI, gradients, avgGrad, nlevels, alfa, beta, noise); // dumpPFS( "FI.pfs", FI, "Y" ); // attenuate gradients pfs::Array2D* Gx = new pfs::Array2DImpl(width, height); pfs::Array2D* Gy = new pfs::Array2DImpl(width, height); for( y=0 ; y 0 ) (*DivG)(x,y) -= (*Gx)(x-1,y); if( y > 0 ) (*DivG)(x,y) -= (*Gy)(x,y-1); } // dumpPFS( "DivG.pfs", DivG, "Y" ); DEBUG_STR << "tmo_fattal02: recovering image" << endl; // solve pde and exponentiate (ie recover compressed image) pfs::Array2D* U = new pfs::Array2DImpl(width, height); solve_pde_multigrid( DivG, U ); // solve_pde_sor( DivG, U ); for( y=0 ; y