diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index 86f08704b..d55e81c7f 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -23,6 +23,7 @@ #include #include #include +#include namespace rtengine{ @@ -92,7 +93,7 @@ RawImage* dfInfo::getRawImage() return ri; } -std::list& dfInfo::getBadPixels() +std::list& dfInfo::getHotPixels() { if( !ri ){ updateRawImage(); @@ -206,8 +207,17 @@ void DFManager::init( Glib::ustring pathname ) safe_build_file_list (dir, names, pathname); dfList.clear(); + bpList.clear(); for (int i=0; iverbose) + printf("Loaded badpixels file %s\n",names[i].c_str()); + continue; + } + try{ + addFileInfo(names[i]); + }catch( std::exception e ){} } // Where multiple shots exist for same group, move filename to list for( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ @@ -229,7 +239,7 @@ void DFManager::init( Glib::ustring pathname ) return; } -bool DFManager::addFileInfo(const Glib::ustring &filename ) +dfInfo *DFManager::addFileInfo(const Glib::ustring &filename ) { Glib::RefPtr file = Gio::File::create_for_path(filename); if (!file ) @@ -248,7 +258,7 @@ bool DFManager::addFileInfo(const Glib::ustring &filename ) dfList_t::iterator iter = dfList.find( key ); if( iter == dfList.end() ){ dfInfo n(filename, ri.make, ri.model,(int)ri.iso_speed,ri.shutter,ri.timestamp); - dfList.insert(std::pair< std::string,dfInfo>( key,n ) ); + iter = dfList.insert(std::pair< std::string,dfInfo>( key,n ) ); }else{ while( iter != dfList.end() && iter->second.key() == key && ABS(iter->second.timestamp - ri.timestamp) >60*60*6 ) // 6 hour difference iter++; @@ -257,14 +267,14 @@ bool DFManager::addFileInfo(const Glib::ustring &filename ) iter->second.pathNames.push_back( filename ); else{ dfInfo n(filename, ri.make, ri.model,(int)ri.iso_speed,ri.shutter,ri.timestamp); - dfList.insert(std::pair< std::string,dfInfo>( key,n ) ); + iter = dfList.insert(std::pair< std::string,dfInfo>( key,n ) ); } } - return true; + return &(iter->second); } } } - return false; + return 0; } void DFManager::getStat( int &totFiles, int &totTemplates) @@ -285,10 +295,10 @@ void DFManager::getStat( int &totFiles, int &totTemplates) * if perfect matches for iso and shutter 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 shutter */ -dfInfo& DFManager::find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ) +dfInfo* DFManager::find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ) { if( dfList.size() == 0 ) - throw std::exception(); + return 0; std::string key( dfInfo::key(mak,mod,isospeed,shut) ); dfList_t::iterator iter = dfList.find( key ); @@ -302,7 +312,7 @@ dfInfo& DFManager::find( const std::string &mak, const std::string &mod, int iso bestDeltaTime = d; } } - return bestMatch->second; + return &(bestMatch->second); }else{ iter = dfList.begin(); dfList_t::iterator bestMatch = iter; @@ -314,36 +324,83 @@ dfInfo& DFManager::find( const std::string &mak, const std::string &mod, int iso bestMatch = iter; } } - return bestMatch->second; + return &(bestMatch->second); } } RawImage* DFManager::searchDarkFrame( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) { - try{ - dfInfo &df = find( mak, mod, iso, shut, t ); - return df.getRawImage(); - }catch( std::exception e){ - return NULL; - } + dfInfo *df = find( mak, mod, iso, shut, t ); + if( df ) + return df->getRawImage(); + else + return 0; } -RawImage* DFManager::searchDarkFrame( Glib::ustring filename ) +RawImage* DFManager::searchDarkFrame( const Glib::ustring filename ) { for ( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ if( iter->second.pathname.compare( filename )==0 ) return iter->second.getRawImage(); } + dfInfo *df = addFileInfo( filename ); + if(df) + return df->getRawImage(); + return 0; +} +std::list *DFManager::getHotPixels ( const Glib::ustring filename ) +{ + for ( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ + if( iter->second.pathname.compare( filename )==0 ) + return &iter->second.getHotPixels(); + } + return 0; +} +std::list *DFManager::getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) +{ + dfInfo *df = find( mak, mod, iso, shut, t ); + if( df ) + return &df->getHotPixels(); + else + return 0; } -std::list DFManager::searchBadPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) +bool DFManager::scanBadPixelsFile( Glib::ustring filename ) { - try{ - dfInfo &df = find( mak, mod, iso, shut, t ); - return df.getBadPixels(); - }catch( std::exception e){ - return std::list(); - } + FILE *file = fopen( filename.c_str(),"r" ); + if( !file ) return false; + int lastdot = filename.find_last_of ('.'); + int dirpos1 = filename.find_last_of ('/'); + int dirpos2 = filename.find_last_of ('\\'); + if( dirpos1 == Glib::ustring::npos && dirpos2== Glib::ustring::npos ) + dirpos1 =0; + else + dirpos1= (dirpos1> dirpos2 ? dirpos1: dirpos2); + std::string makmodel(filename,dirpos1+1,lastdot-(dirpos1+1) ); + std::list bp; + char line[256]; + while( fgets(line,sizeof(line),file ) ){ + int x,y; + if( sscanf(line,"%d %d",&x,&y) == 2 ) + bp.push_back( badPix(x,y) ); + } + if( bp.size()>0 ){ + bpList[ makmodel ] = bp; + return true; + } + return false; +} + +std::list *DFManager::getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial) +{ + std::ostringstream s; + s << mak << " " <0) + s << " " << serial; + bpList_t::iterator iter = bpList.find( s.str() ); + if( iter != bpList.end() ) + return &(iter->second); + return 0; } // Global variable @@ -351,3 +408,4 @@ DFManager dfm; } + diff --git a/rtengine/dfmanager.h b/rtengine/dfmanager.h index f15070b06..3dd269598 100644 --- a/rtengine/dfmanager.h +++ b/rtengine/dfmanager.h @@ -29,7 +29,7 @@ class dfInfo public: Glib::ustring pathname; // filename of dark frame - std::list pathNames; // other similar dark frames, used to mediate + std::list pathNames; // other similar dark frames, used for average std::string maker; ///< manufacturer std::string model; ///< model int iso; ///< ISO (gain) @@ -55,11 +55,11 @@ public: std::string key(){ return key( maker,model,iso,shutter); } RawImage *getRawImage(); - std::list &getBadPixels(); + std::list &getHotPixels(); protected: RawImage *ri; ///< Dark Frame raw data - std::list badPixels; ///< Unreliable pixels + std::list badPixels; ///< Extracted hot pixels void updateBadPixelList( RawImage *df ); void updateRawImage(); @@ -72,16 +72,21 @@ public: Glib::ustring getPathname(){ return currentPath; }; void getStat( int &totFiles, int &totTemplate); RawImage *searchDarkFrame( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ); - RawImage *searchDarkFrame( Glib::ustring filename ); - std::list searchBadPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ); + RawImage *searchDarkFrame( const Glib::ustring filename ); + std::list *getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ); + std::list *getHotPixels ( const Glib::ustring filename ); + std::list *getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial); protected: typedef std::multimap dfList_t; + typedef std::map > bpList_t; dfList_t dfList; + bpList_t bpList; bool initialized; Glib::ustring currentPath; - bool addFileInfo(const Glib::ustring &filename ); - dfInfo &find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ); + dfInfo *addFileInfo(const Glib::ustring &filename ); + dfInfo *find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ); + bool scanBadPixelsFile( Glib::ustring filename ); }; extern DFManager dfm; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index c23595d70..d8fcfca71 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -59,7 +59,6 @@ RawImageSource::RawImageSource () ,border(4) ,rawData(NULL) ,ri(NULL) -,df(NULL) { hrmap[0] = NULL; hrmap[1] = NULL; @@ -76,9 +75,6 @@ RawImageSource::~RawImageSource () { if (ri) { delete ri; } - if(df){ - delete df; - } if (green) freeArray(green, H); @@ -328,95 +324,67 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, Previe isrcMutex.unlock (); } -void RawImageSource::cfaCleanFromList( const std::list &bpList ) +/* cfaCleanFromMap: correct raw pixels looking at the bitmap + * takes into consideration if there are multiple bad pixels in the neighborhood + */ +int RawImageSource::cfaCleanFromMap( BYTE* bitmapBads ) { - int rr, cc; - unsigned short gin,g[8]; - float eps=1e-10;//tolerance to avoid dividing by zero - float p[8]; + const int border=4; + double eps=1e-10; + int bmpW= (W/8+ (W%8?1:0)); + int counter=0; + for( int row = 0; row < H; row++ ){ + for(int col = 0; col ::const_iterator iter=bpList.begin(); iter != bpList.end(); iter++ ){ - rr = iter->y; - if( rr<4 || rr>=H-4 ) - continue; - cc = iter->x; - if( cc<4 || cc>=W-4 ) - continue; + if( !bitmapBads[ row *bmpW + col/8] ){ col+=7;continue; } //optimization - //pixel neighbor average - gin=rawData[rr][cc]; - g[0]=rawData[rr-2][cc-2]; - g[1]=rawData[rr-2][cc]; - g[2]=rawData[rr-2][cc+2]; - g[3]=rawData[rr][cc-2]; - g[4]=rawData[rr][cc+2]; - g[5]=rawData[rr+2][cc-2]; - g[6]=rawData[rr+2][cc]; - g[7]=rawData[rr+2][cc+2]; + if( !(bitmapBads[ row *bmpW + col/8] & (1<=H || col+dx<0 || row+dx>=W ) continue; + if (bitmapBads[ (row+dy) *bmpW + (col+dx)/8] & (1<<(col+dx)%8)) continue; - rawData[rr][cc] = (int)((g[0]*p[0]+g[1]*p[1]+g[2]*p[2]+g[3]*p[3]+g[4]*p[4]+ g[5]*p[5]+g[6]*p[6]+g[7]*p[7])/(p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7])); + double dirwt = 1/( ( rawData[row+dy][col+dx]- rawData[row][col])*( rawData[row+dy][col+dx]- rawData[row][col])+eps); + wtdsum += dirwt* rawData[row+dy][col+dx]; + norm += dirwt; + } + } + if (norm > 0.){ + rawData[row][col]= wtdsum / norm;//low pass filter + counter++; + } + } } + return counter; } - -void RawImageSource::cfa_clean(float thresh) //Emil's hot/dead pixel removal -- only filters egregiously impulsive pixels - { - // local variables - int rr, cc; - int gin, g[8]; - - float eps=1e-10;//tolerance to avoid dividing by zero - float p[8]; - float pixave, pixratio; - // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //The cleaning algorithm starts here - - for (rr=4; rr < H-4; rr++) - for (cc=4; cc < W-4; cc++) { - - //pixel neighbor average - gin=rawData[rr][cc]; - g[0]=rawData[rr-2][cc-2]; - g[1]=rawData[rr-2][cc]; - g[2]=rawData[rr-2][cc+2]; - g[3]=rawData[rr][cc-2]; - g[4]=rawData[rr][cc+2]; - g[5]=rawData[rr+2][cc-2]; - g[6]=rawData[rr+2][cc]; - g[7]=rawData[rr+2][cc+2]; - - pixave=(float)(g[0]+g[1]+g[2]+g[3]+g[4]+g[5]+g[6]+g[7])/8; - pixratio=MIN(gin,pixave)/(eps+MAX(gin,pixave)); - - if (pixratio > thresh) continue; - - p[0]=1/(eps+fabs(g[0]-gin)+fabs(g[0]-rawData[rr-4][cc-4])+fabs(rawData[rr-1][cc-1]-rawData[rr-3][cc-3])); - p[1]=1/(eps+fabs(g[1]-gin)+fabs(g[1]-rawData[rr-4][cc])+fabs(rawData[rr-1][cc]-rawData[rr-3][cc])); - p[2]=1/(eps+fabs(g[2]-gin)+fabs(g[2]-rawData[rr-4][cc+4])+fabs(rawData[rr-1][cc+1]-rawData[rr-3][cc+3])); - p[3]=1/(eps+fabs(g[3]-gin)+fabs(g[3]-rawData[rr][cc-4])+fabs(rawData[rr][cc-1]-rawData[rr][cc-3])); - p[4]=1/(eps+fabs(g[4]-gin)+fabs(g[4]-rawData[rr][cc+4])+fabs(rawData[rr][cc+1]-rawData[rr][cc+3])); - p[5]=1/(eps+fabs(g[5]-gin)+fabs(g[5]-rawData[rr+4][cc-4])+fabs(rawData[rr+1][cc-1]-rawData[rr+3][cc-3])); - p[6]=1/(eps+fabs(g[6]-gin)+fabs(g[6]-rawData[rr+4][cc])+fabs(rawData[rr+1][cc]-rawData[rr+3][cc])); - p[7]=1/(eps+fabs(g[7]-gin)+fabs(g[7]-rawData[rr+4][cc+4])+fabs(rawData[rr+1][cc+1]-rawData[rr+3][cc+3])); - - rawData[rr][cc] = (int)((g[0]*p[0]+g[1]*p[1]+g[2]*p[2]+g[3]*p[3]+g[4]*p[4]+ \ - g[5]*p[5]+g[6]*p[6]+g[7]*p[7])/(p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7])); - - }//now impulsive values have been corrected - - - // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - } +/* Search for hot or dead pixels in the image and update the map + * For each pixel compare its value to the average of similar color surrounding + * (Taken from Emil Martinec idea) + */ +int RawImageSource::findHotDeadPixel( BYTE *bpMap, float thresh) +{ + int bmpW= (W/8+ (W%8?1:0)); + float eps=1e-10;//tolerance to avoid dividing by zero + int counter=0; + for (int rr=2; rr < H-2; rr++) + for (int cc=2; cc < W-2; cc++) { + + int gin=rawData[rr][cc]; + int pixave = (rawData[rr-2][cc-2]+rawData[rr-2][cc]+rawData[rr-2][cc+2]+rawData[rr][cc-2]+rawData[rr][cc+2]+rawData[rr+2][cc-2]+rawData[rr+2][cc]+rawData[rr+2][cc+2])/8; + float pixratio=MIN(gin,pixave)/(eps+MAX(gin,pixave)); + + if (pixratio > thresh) continue; + + // mark the pixel as "bad" + bpMap[rr*bmpW+cc/8 ] |= 1<<(cc%8); + counter++; + } + return counter; +} void RawImageSource::rotateLine (unsigned short* line, unsigned short** channel, int tran, int i, int w, int h) { @@ -802,31 +770,33 @@ int RawImageSource::load (Glib::ustring fname) { void RawImageSource::preprocess (const RAWParams &raw) { Glib::ustring newDF = raw.dark_frame; - Glib::ustring currentDF = (df ? df->fname : ""); + RawImage *rid=NULL; if (!raw.df_autoselect) { - if (newDF != currentDF) { - if (df) - delete df; - df = NULL; - if (newDF.length() > 0) { - df = new RawImage(newDF); - int res = df->loadRaw(); - if (res) { - delete df; - df = NULL; - } - } - } - - copyOriginalPixels(ri, df); + if( raw.dark_frame.size()>0) + rid = dfm.searchDarkFrame( raw.dark_frame ); }else{ - RawImage *rid = dfm.searchDarkFrame( ri->make, ri->model, ri->iso_speed, ri->shutter, ri->timestamp); - copyOriginalPixels(ri, rid); + rid = dfm.searchDarkFrame( ri->make, ri->model, ri->iso_speed, ri->shutter, ri->timestamp); } - if(!raw.hotdeadpix_filt && raw.df_autoselect ){ - std::list bp = dfm.searchBadPixels( ri->make, ri->model, ri->iso_speed, ri->shutter, ri->timestamp); - cfaCleanFromList(bp); + copyOriginalPixels(ri, rid); + size_t widthBitmap = (ri->width/8+ (ri->width%8?1:0)); + size_t dimBitmap = widthBitmap*ri->height; + + BYTE *bitmapBads = new BYTE [ dimBitmap ]; + std::list *bp = dfm.getBadPixels( ri->make, ri->model, std::string("") ); + if( bp ){ + for(std::list::iterator iter = bp->begin(); iter != bp->end(); iter++) + bitmapBads[ widthBitmap * (iter->y) + (iter->x)/8] |= 1<<(iter->x%8); } + bp = 0; + if( raw.df_autoselect ) + bp = dfm.getHotPixels( ri->make, ri->model, ri->iso_speed, ri->shutter, ri->timestamp); + else if( raw.dark_frame.size()>0 ) + bp = dfm.getHotPixels( raw.dark_frame ); + if(bp) + for(std::list::iterator iter = bp->begin(); iter != bp->end(); iter++) + bitmapBads[ widthBitmap *iter->y + iter->x/8] |= 1<<(iter->x%8); + + preInterpolate(false); scaleColors( false,true); @@ -840,7 +810,7 @@ void RawImageSource::preprocess (const RAWParams &raw) double tg = icoeff[1][0] * cam_r + icoeff[1][1] * cam_g + icoeff[1][2] * cam_b; double tb = icoeff[2][0] * cam_r + icoeff[2][1] * cam_g + icoeff[2][2] * cam_b; - defGain = log(ri->defgain) / log(2.0); //\TODO rivedere l'assegnamento di ri->defgain che dovrebbe essere "costante" + defGain = log(ri->defgain) / log(2.0); //\TODO ri->defgain should be "costant" // check if it is an olympus E camera, if yes, compute G channel pre-compensation factors if ( raw.greenthresh || (((idata->getMake().size()>=7 && idata->getMake().substr(0,7)=="OLYMPUS" && idata->getModel()[0]=='E') || (idata->getMake().size()>=9 && idata->getMake().substr(0,7)=="Panasonic")) && raw.dmethod != RAWParams::methodstring[ RAWParams::vng4] && ri->filters) ) { @@ -880,9 +850,10 @@ void RawImageSource::preprocess (const RAWParams &raw) plistener->setProgressStr ("Hot/Dead Pixel Filter..."); plistener->setProgress (0.0); } - - cfa_clean(0.1); + findHotDeadPixel( bitmapBads,0.1 ); } + cfaCleanFromMap( bitmapBads ); + delete [] bitmapBads; if ( raw.linenoise >0 ) { if (plistener) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 7571b9779..2ea80fed1 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -74,7 +74,6 @@ class RawImageSource : public ImageSource { cmsHPROFILE embProfile; RawImage* ri; // Copy of raw pixels - RawImage* df; // Darkframe pixels (if present) // to accelerate CIELAB conversion: double lc00, lc01, lc02, lc10, lc11, lc12, lc20, lc21, lc22; @@ -148,8 +147,8 @@ class RawImageSource : public ImageSource { int LinEqSolve( int nDim, float* pfMatr, float* pfVect, float* pfSolution);//Emil's CA auto correction void CA_correct_RT (); - void cfaCleanFromList( const std::list &bpList ); - void cfa_clean (float thresh);//Emil's hot/dead pixel filter + int cfaCleanFromMap( BYTE* bitmapBads ); + int findHotDeadPixel( BYTE *bpMap, float thresh); void ddct8x8s(int isgn, float **a); void cfa_linedn (float linenoiselevel);//Emil's line denoise