diff --git a/rtengine/ffmanager.cc b/rtengine/ffmanager.cc new file mode 100644 index 000000000..d669beb39 --- /dev/null +++ b/rtengine/ffmanager.cc @@ -0,0 +1,319 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee 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 3 of the License, or + * (at your option) any later version. + * + * RawTherapee 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 RawTherapee. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rtengine{ + +extern Settings* settings; + +// *********************** class ffInfo ************************************** + +inline ffInfo& ffInfo::operator =(const ffInfo &o){ + pathname = o.pathname; + maker = o.maker; + model = o.model; + iso = o.iso; + shutter = o.shutter; + timestamp = o.timestamp; + if( ri ){ + delete ri; + ri = NULL; + } + return *this; +} + +bool ffInfo::operator <(const ffInfo &e2) const +{ + if( this->maker.compare( e2.maker) >=0 ) + return false; + if( this->model.compare( e2.model) >=0 ) + return false; + if( this->iso >= e2.iso ) + return false; + if( this->shutter >= e2.shutter ) + return false; + if( this->timestamp >= e2.timestamp ) + return false; + return true; +} + +std::string ffInfo::key(const std::string &mak, const std::string &mod, int iso, double shut, double apert ) +{ + std::ostringstream s; + s << mak << " " << mod << " "; + s.width(5); + s << iso << "ISO "; + s.precision( 2 ); + s.width(4); + s << shut << "s"; + return s.str(); +} + +double ffInfo::distance(const std::string &mak, const std::string &mod, int iso, double shutter, double aperture) const +{ + if( this->maker.compare( mak) != 0 ) + return INFINITY; + if( this->model.compare( mod) != 0 ) + return INFINITY; + double dAperture = 2*(log(this->aperture) - log(aperture))/log(2);//more important for vignette + double dISO = (log(this->iso/100.) - log(iso/100.))/log(2);//more important for PRNU + //double dShutter = (log(this->shutter) - log(shutter))/log(2); + return sqrt( dISO*dISO + dAperture*dAperture); +} + +RawImage* ffInfo::getRawImage() +{ + if(ri) + return ri; + updateRawImage(); + + return ri; +} + +/* updateRawImage() load into ri the actual pixel data from pathname if there is a single shot + * otherwise load each file from the pathNames list and extract a template from the media; + * the first file is used also for reading all information other than pixels + */ +void ffInfo::updateRawImage() +{ + typedef unsigned int acc_t; + if( pathNames.size() >0 ){ + std::list::iterator iName = pathNames.begin(); + ri = new RawImage(*iName); // First file used also for extra pixels informations (width,height, shutter, filters etc.. ) + if( ri->loadRaw(true)){ + delete ri; + ri=NULL; + }else{ + int H = ri->get_height(); + int W = ri->get_width(); + ri->compress_image(); + int rSize = W*(ri->isBayer()?1:3); + acc_t **acc = new acc_t*[H]; + for( int row=0; rowdata[row][col]; + int nFiles = 1; // First file data already loaded + + for( iName++; iName != pathNames.end(); iName++){ + RawImage* temp = new RawImage(*iName); + if( !temp->loadRaw(true)){ + temp->compress_image(); //\ TODO would be better working on original, because is temporary + nFiles++; + if( ri->isBayer() ){ + for( int row=0; rowdata[row][col]; + } + }else{ + for( int row=0; rowdata[row][3*col+0]; + acc[row][3*col+1] += temp->data[row][3*col+1]; + acc[row][3*col+2] += temp->data[row][3*col+2]; + } + } + } + } + delete temp; + } + for (int row = 0; row < H; row++){ + for (int col = 0; col < rSize; col++) + ri->data[row][col] = acc[row][col] / nFiles; + delete [] acc[row]; + } + delete [] acc; + } + }else{ + ri = new RawImage(pathname); + if( ri->loadRaw(true)){ + delete ri; + ri=NULL; + }else + ri->compress_image(); + } +} + + +// ************************* class FFManager ********************************* + +void FFManager::init( Glib::ustring pathname ) +{ + std::vector names; + Glib::RefPtr dir = Gio::File::create_for_path (pathname); + if( dir && !dir->query_exists()) + return; + safe_build_file_list (dir, names, pathname); + + ffList.clear(); + for (int i=0; isecond; + if( i.pathNames.size()>0 && !i.pathname.empty() ){ + i.pathNames.push_back( i.pathname ); + i.pathname.clear(); + } + if( settings->verbose ){ + if( !i.pathname.empty() ) + printf( "%s: %s\n",i.key().c_str(),i.pathname.c_str()); + else{ + printf( "%s: MEAN of \n ",i.key().c_str()); + for( std::list::iterator iter = i.pathNames.begin(); iter != i.pathNames.end();iter++ ) + printf( "%s, ", iter->c_str() ); + printf("\n"); + } + } + } + currentPath = pathname; + return; +} + +ffInfo *FFManager::addFileInfo(const Glib::ustring &filename ) +{ + Glib::RefPtr file = Gio::File::create_for_path(filename); + if (!file ) + return false; + if( !file->query_exists()) + return false; + Glib::RefPtr info = safe_query_file_info(file); + if (info && info->get_file_type() != Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || !options.fbShowHidden)) { + int lastdot = info->get_name().find_last_of ('.'); + if (options.is_extention_enabled(lastdot!=Glib::ustring::npos ? info->get_name().substr (lastdot+1) : "")){ + RawImage ri(filename); + int res = ri.loadRaw(false); // Read informations about shot + if( !res ){ + /* Files are added in the map, divided by same maker/model,ISO and shutter*/ + std::string key( ffInfo::key(ri.get_maker(), ri.get_model(),(int)ri.get_ISOspeed(),ri.get_shutter(),ri.get_aperture()) ); + ffList_t::iterator iter = ffList.find( key ); + if( iter == ffList.end() ){ + ffInfo n(filename, ri.get_maker(), ri.get_model(),(int)ri.get_ISOspeed(),ri.get_shutter(),ri.get_aperture(),ri.get_timestamp()); + iter = ffList.insert(std::pair< std::string,ffInfo>( key,n ) ); + }else{ + while( iter != ffList.end() && iter->second.key() == key && ABS(iter->second.timestamp - ri.get_timestamp()) >60*60*6 ) // 6 hour difference + iter++; + + if( iter != ffList.end() ) + iter->second.pathNames.push_back( filename ); + else{ + ffInfo n(filename, ri.get_maker(), ri.get_model(),(int)ri.get_ISOspeed(),ri.get_shutter(),ri.get_aperture(),ri.get_timestamp()); + iter = ffList.insert(std::pair< std::string,ffInfo>( key,n ) ); + } + } + return &(iter->second); + } + } + } + return 0; +} + +void FFManager::getStat( int &totFiles, int &totTemplates) +{ + totFiles=0; + totTemplates=0; + for( ffList_t::iterator iter = ffList.begin(); iter != ffList.end();iter++ ){ + ffInfo &i = iter->second; + if( i.pathname.empty() ){ + totTemplates++; + totFiles += i.pathNames.size(); + }else + totFiles++; + } +} + +/* The search for the best match is twofold: + * if perfect matches for iso and aperture are found, then the list is scanned for lesser distance in time + * otherwise if no match is found, the whole list is searched for lesser distance in iso and aperture + */ +ffInfo* FFManager::find( const std::string &mak, const std::string &mod, int isospeed, double shut, double apert, time_t t ) +{ + if( ffList.size() == 0 ) + return 0; + std::string key( ffInfo::key(mak,mod,isospeed,shut,apert) ); + ffList_t::iterator iter = ffList.find( key ); + + if( iter != ffList.end() ){ + ffList_t::iterator bestMatch = iter; + time_t bestDeltaTime = ABS(iter->second.timestamp - t); + for(iter++; iter != ffList.end() && !key.compare( iter->second.key() ); iter++ ){ + time_t d = ABS(iter->second.timestamp - t ); + if( d< bestDeltaTime ){ + bestMatch = iter; + bestDeltaTime = d; + } + } + return &(bestMatch->second); + }else{ + iter = ffList.begin(); + ffList_t::iterator bestMatch = iter; + double bestD = iter->second.distance( mak, mod, isospeed, shut, apert ); + for( iter++; iter != ffList.end();iter++ ){ + double d = iter->second.distance( mak, mod, isospeed, shut, apert ); + if( d < bestD ){ + bestD = d; + bestMatch = iter; + } + } + return &(bestMatch->second); + } +} + +RawImage* FFManager::searchFlatField( const std::string &mak, const std::string &mod, int iso, double shut, double apert, time_t t ) +{ + ffInfo *ff = find( mak, mod, iso, shut, apert, t ); + if( ff ) + return ff->getRawImage(); + else + return 0; +} + +RawImage* FFManager::searchFlatField( const Glib::ustring filename ) +{ + for ( ffList_t::iterator iter = ffList.begin(); iter != ffList.end();iter++ ){ + if( iter->second.pathname.compare( filename )==0 ) + return iter->second.getRawImage(); + } + ffInfo *ff = addFileInfo( filename ); + if(ff) + return ff->getRawImage(); + return 0; +} + + +// Global variable +FFManager ffm; + + +} + diff --git a/rtengine/ffmanager.h b/rtengine/ffmanager.h new file mode 100644 index 000000000..8c51d8527 --- /dev/null +++ b/rtengine/ffmanager.h @@ -0,0 +1,87 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee 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 3 of the License, or + * (at your option) any later version. + * + * RawTherapee 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 RawTherapee. If not, see . + */ +#include +#include +#include +#include +#include + +namespace rtengine{ + +class ffInfo +{ +public: + + Glib::ustring pathname; // filename of flat field + std::list pathNames; // other similar dark frames, used for average + std::string maker; ///< manufacturer + std::string model; ///< model + int iso; ///< ISO (gain) + double shutter; ///< shutter or exposure time in sec + double aperture; ///< aperture in stops + time_t timestamp; ///< seconds since 1 Jan 1970 + + + ffInfo(const Glib::ustring &name, const std::string &mak, const std::string &mod,int iso,double shut,double apert,time_t t) + :pathname(name),maker(mak),model(mod),iso(iso),shutter(shut),aperture(apert),timestamp(t),ri(NULL){} + + ffInfo( const ffInfo &o) + :pathname(o.pathname),maker(o.maker),model(o.model),iso(o.iso),shutter(o.shutter),aperture(o.aperture),timestamp(o.timestamp),ri(NULL){} + ~ffInfo() { if( ri ) delete ri; } + + + ffInfo &operator =(const ffInfo &o); + bool operator <(const ffInfo &e2) const; + + // Calculate virtual distance between two shots; different model return infinite + double distance(const std::string &mak, const std::string &mod, int iso, double shutter, double aperture) const; + + static std::string key(const std::string &mak, const std::string &mod, int iso, double shut, double apert ); + std::string key(){ return key( maker,model,iso,shutter,aperture); } + + RawImage *getRawImage(); + +protected: + RawImage *ri; ///< Flat Field raw data + + void updateRawImage(); +}; + +class FFManager +{ +public: + void init( Glib::ustring pathname ); + Glib::ustring getPathname(){ return currentPath; }; + void getStat( int &totFiles, int &totTemplate); + RawImage *searchFlatField( const std::string &mak, const std::string &mod, int iso, double shut, double apert, time_t t ); + RawImage *searchFlatField( const Glib::ustring filename ); + +protected: + typedef std::multimap ffList_t; + typedef std::map > bpList_t; + ffList_t ffList; + bool initialized; + Glib::ustring currentPath; + ffInfo *addFileInfo(const Glib::ustring &filename ); + ffInfo *find( const std::string &mak, const std::string &mod, int isospeed, double shut, double apert, time_t t ); +}; + +extern FFManager ffm; + +}