From 13a49eb7b3b27ec89fcbceacbb965aa1fbfe210d Mon Sep 17 00:00:00 2001 From: Ingo Date: Wed, 10 Sep 2014 14:55:58 +0200 Subject: [PATCH] Optimization for dark frames and hot/dead pixel detection/interpolation, Issue 2486 --- AUTHORS.txt | 2 + rtdata/languages/Deutsch | 10 ++- rtdata/languages/Francais | 9 +- rtdata/languages/default | 12 ++- rtengine/dfmanager.cc | 115 ++++++++++++++++--------- rtengine/dfmanager.h | 12 +-- rtengine/improccoordinator.cc | 2 +- rtengine/procevents.h | 3 +- rtengine/procparams.cc | 15 +++- rtengine/procparams.h | 3 +- rtengine/rawimage.h | 17 ++-- rtengine/rawimagesource.cc | 154 ++++++++++++++++++++++++++-------- rtengine/rawimagesource.h | 4 +- rtengine/refreshmap.cc | 6 +- rtgui/paramsedited.cc | 11 ++- rtgui/paramsedited.h | 3 +- rtgui/partialpastedlg.cc | 22 +++-- rtgui/partialpastedlg.h | 5 +- rtgui/preprocess.cc | 80 ++++++++++++------ rtgui/preprocess.h | 12 +-- 20 files changed, 343 insertions(+), 154 deletions(-) diff --git a/AUTHORS.txt b/AUTHORS.txt index a1733a88e..1f7890d8b 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -8,6 +8,7 @@ Developement contributors, in last name alphabetical order: Martin Burri Javier Celaya Jacques Desmis + Pavlov Dmitry Oliver Duis Maciek Dworak Michael Ezra @@ -36,6 +37,7 @@ Other contributors (profiles, ideas, mockups, testing, forum activity, translati Thorsten Bartolomäus Patrik Brunner Fernando Carello + Pat David Reine Edvardsson André Gauthier Sébastien Guyader diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch index ae589f096..04d53f76b 100644 --- a/rtdata/languages/Deutsch +++ b/rtdata/languages/Deutsch @@ -623,7 +623,8 @@ PARTIALPASTE_METAICMGROUP;Gruppe Metadaten / ICM PARTIALPASTE_PCVIGNETTE;Vignettierungsfilter PARTIALPASTE_PERSPECTIVE;Perspektive PARTIALPASTE_PREPROCESS_GREENEQUIL;Vorverarbeitung: Grün-Ausgleich -PARTIALPASTE_PREPROCESS_HOTDEADPIXFILT;Vorverarbeitung: Hot/Dead-Pixel-Filter anwenden +PARTIALPASTE_PREPROCESS_HOTPIXFILT;Vorverarbeitung: Hot-Pixel-Filter +PARTIALPASTE_PREPROCESS_DEADPIXFILT;Vorverarbeitung: Dead-Pixel-Filter PARTIALPASTE_PREPROCESS_LINEDENOISE;Vorverarbeitung: Zeilenrauschfilter PARTIALPASTE_RAWCACORR_AUTO;Chromatische Aberration: Automatische Korrektur PARTIALPASTE_RAWCACORR_CABLUE;Chromatische Aberration: Blau @@ -633,7 +634,7 @@ PARTIALPASTE_RAWEXPOS_LINEAR;RAW-Weiß/Schwarz-Punkt: Linearer Korrekturfaktor PARTIALPASTE_RAWEXPOS_PRESER;RAW-Weiß/Schwarz-Punkt: Lichter bewahren (EV) PARTIALPASTE_RAWGROUP;Gruppe RAW PARTIALPASTE_RAW_ALLENHANCE;Farbinterpolation: Artifakt-/Rauschminderung -PARTIALPASTE_RAW_DCBENHANCE;Farbinterpolation: DCB-Verfeinerungsschritt durchführen +PARTIALPASTE_RAW_DCBENHANCE;Farbinterpolation: DCB-Verfeinerungsschritt PARTIALPASTE_RAW_DCBITERATIONS;Farbinterpolation: Anzahl der DCB-Iterationen PARTIALPASTE_RAW_DMETHOD;Farbinterpolation: Methode PARTIALPASTE_RAW_FALSECOLOR;Farbinterpolation: Falschfarbenunterdrückung Stufen @@ -1206,7 +1207,8 @@ TP_PERSPECTIVE_HORIZONTAL;Horizontal TP_PERSPECTIVE_LABEL;Perspektive TP_PERSPECTIVE_VERTICAL;Vertikal TP_PREPROCESS_GREENEQUIL;Grün-Ausgleich -TP_PREPROCESS_HOTDEADPIXFILT;Hot/Dead-Pixel-Filter anwenden +TP_PREPROCESS_HOTPIXFILT;Hot-Pixel-Filter +TP_PREPROCESS_DEADPIXFILT;Dead-Pixel-Filter TP_PREPROCESS_HOTDEADPIXTHRESH;Hot/Dead-Pixel-Erkennung\nSchwellenwert TP_PREPROCESS_LABEL;Vorverarbeitung TP_PREPROCESS_LINEDENOISE;Zeilenrauschfilter @@ -1223,7 +1225,7 @@ TP_RAWEXPOS_LINEAR;Weißpunkt: Linearer\nKorrekturfaktor TP_RAWEXPOS_PRESER;Weißpunkt: Lichter\nbewahrende Korrektur (EV) TP_RAWEXPOS_TWOGREEN;Grün-Werte automatisch angleichen TP_RAW_ALLENHANCE;Artifakt-/Rauschminderung nach\nFarbinterpolation durchführen -TP_RAW_DCBENHANCE;DCB-Verfeinerungsschritt durchführen +TP_RAW_DCBENHANCE;DCB-Verfeinerungsschritt TP_RAW_DCBITERATIONS;Anzahl der DCB-Iterationen TP_RAW_DMETHOD;Methode TP_RAW_FALSECOLOR;Falschfarbenunterdrückung\nStufen diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index ab7ff98e5..742358059 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -690,7 +690,8 @@ PARTIALPASTE_METAICMGROUP;Réglages des Métadonnées/ICM PARTIALPASTE_PCVIGNETTE;Filtre Vignettage PARTIALPASTE_PERSPECTIVE;Perspective PARTIALPASTE_PREPROCESS_GREENEQUIL;Équilibrage du vert -PARTIALPASTE_PREPROCESS_HOTDEADPIXFILT;Filtrage des pixels chauds/morts +PARTIALPASTE_PREPROCESS_HOTPIXFILT;Filtrage des pixels chauds +PARTIALPASTE_PREPROCESS_DEADPIXFILT;Filtrage des pixels morts PARTIALPASTE_PREPROCESS_LINEDENOISE;Filtre de bruit de ligne PARTIALPASTE_RAWCACORR_AUTO;Corr. auto. de l'aberr. chromatique PARTIALPASTE_RAWCACORR_CABLUE;Aberr. chromatique bleu @@ -1360,8 +1361,10 @@ TP_PERSPECTIVE_VERTICAL;Verticale TP_PFCURVE_CURVEEDITOR_CH;Teinte TP_PFCURVE_CURVEEDITOR_CH_TOOLTIP;Contrôle la force du défrangeage en fonction de la couleur. En haut = action maxi, en bas = pas d'action sur la couleur. TP_PREPROCESS_GREENEQUIL;Équilibrage du vert -TP_PREPROCESS_HOTDEADPIXFILT;Filtrer les pixels chauds/morts -TP_PREPROCESS_HOTDEADPIXFILT_TOOLTIP;Essaie de supprimer les pixels chauds/morts +TP_PREPROCESS_HOTPIXFILT;Filtrer les pixels chauds +TP_PREPROCESS_DEADPIXFILT;Filtrer les pixels morts +TP_PREPROCESS_HOTPIXFILT_TOOLTIP;Essaie de supprimer les pixels chauds +TP_PREPROCESS_DEADPIXFILT_TOOLTIP;Essaie de supprimer les pixels morts TP_PREPROCESS_LABEL;Traitement pre-dématriçage TP_PREPROCESS_LINEDENOISE;Filtre de bruit de ligne TP_PREPROCESS_NO_FOUND;Aucun trouvé diff --git a/rtdata/languages/default b/rtdata/languages/default index 86fb524a6..993868fa6 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -319,7 +319,7 @@ HISTORY_MSG_95;Lab - Chromaticity HISTORY_MSG_96;'a' Curve HISTORY_MSG_97;'b' Curve HISTORY_MSG_98;Demosaicing Method -HISTORY_MSG_99;Hot/Dead pixel filter +HISTORY_MSG_99;Hot pixel filter HISTORY_MSG_100;Saturation HISTORY_MSG_101;HSV - Hue HISTORY_MSG_102;HSV - Saturation @@ -517,6 +517,7 @@ HISTORY_MSG_294;Film Simulation - Strength HISTORY_MSG_295;Film Simulation - Film HISTORY_MSG_296;NR - Modulate luminance HISTORY_MSG_297;NR - Quality +HISTORY_MSG_298;Dead pixel filter HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOTS;Snapshots @@ -686,7 +687,8 @@ PARTIALPASTE_METAICMGROUP;Metadata/Color Management Settings PARTIALPASTE_PCVIGNETTE;Vignette filter PARTIALPASTE_PERSPECTIVE;Perspective PARTIALPASTE_PREPROCESS_GREENEQUIL;Green equilibration -PARTIALPASTE_PREPROCESS_HOTDEADPIXFILT;Apply hot/dead pixel filter +PARTIALPASTE_PREPROCESS_HOTPIXFILT;Apply hot pixel filter +PARTIALPASTE_PREPROCESS_DEADPIXFILT;Apply dead pixel filter PARTIALPASTE_PREPROCESS_LINEDENOISE;Line noise filter PARTIALPASTE_RAWCACORR_AUTO;CA auto-correction PARTIALPASTE_RAWCACORR_CABLUE;CA blue @@ -1376,8 +1378,10 @@ TP_PERSPECTIVE_VERTICAL;Vertical TP_PFCURVE_CURVEEDITOR_CH;Hue TP_PFCURVE_CURVEEDITOR_CH_TOOLTIP;Controls defringe strength by color.\nHigher = more,\nLower = less. TP_PREPROCESS_GREENEQUIL;Green Equilibration -TP_PREPROCESS_HOTDEADPIXFILT;Hot/Dead pixel filter -TP_PREPROCESS_HOTDEADPIXFILT_TOOLTIP;Tries to suppress hot and dead pixels. +TP_PREPROCESS_HOTPIXFILT;Hot pixel filter +TP_PREPROCESS_HOTPIXFILT_TOOLTIP;Tries to suppress hot pixels. +TP_PREPROCESS_DEADPIXFILT;Dead pixel filter +TP_PREPROCESS_DEADPIXFILT_TOOLTIP;Tries to suppress dead pixels. TP_PREPROCESS_LABEL;Preprocessing TP_PREPROCESS_LINEDENOISE;Line Noise Filter TP_PREPROCESS_NO_FOUND;None found diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index 4d95fa93e..bb3a73728 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -26,7 +26,7 @@ #include #include #include "imagedata.h" - + namespace rtengine{ extern const Settings* settings; @@ -95,7 +95,7 @@ RawImage* dfInfo::getRawImage() return ri; } -std::list& dfInfo::getHotPixels() +std::vector& dfInfo::getHotPixels() { if( !ri ){ updateRawImage(); @@ -108,7 +108,7 @@ std::list& dfInfo::getHotPixels() * the first file is used also for reading all information other than pixels */ void dfInfo::updateRawImage() -{ +{ typedef unsigned int acc_t; if( !pathNames.empty() ){ std::list::iterator iName = pathNames.begin(); @@ -171,27 +171,37 @@ void dfInfo::updateRawImage() } void dfInfo::updateBadPixelList( RawImage *df ) -{ - const int threshold=10; - if( ri->getSensorType()!=ST_NONE ){ +{ + const float threshold=10.f/8.f; + if( ri->getSensorType()!=ST_NONE ){ + std::vector badPixelsTemp; + +#pragma omp parallel +{ + std::vector badPixelsThread; +#pragma omp for nowait for( int row=2; rowget_height()-2; row++) for( int col=2; col < df->get_width()-2; col++){ - int m = (df->data[row-2][col-2] + df->data[row-2][col] + df->data[row-2][col+2]+ + float m = (df->data[row-2][col-2] + df->data[row-2][col] + df->data[row-2][col+2]+ df->data[row][col-2] + df->data[row][col+2]+ - df->data[row+2][col-2] + df->data[row+2][col] + df->data[row+2][col+2])/8; - if( df->data[row][col]/threshold > m ) - badPixels.push_back( badPix(col,row) ); - } + df->data[row+2][col-2] + df->data[row+2][col] + df->data[row+2][col+2]); + if( df->data[row][col] > m*threshold ) + badPixelsThread.push_back( badPix(col,row) ); + } +#pragma omp critical + badPixelsTemp.insert(badPixelsTemp.end(),badPixelsThread.begin(),badPixelsThread.end()); +} + badPixels.insert(badPixels.end(),badPixelsTemp.begin(),badPixelsTemp.end()); }else{ for( int row=1; rowget_height()-1; row++) for( int col=1; col < df->get_width()-1; col++){ - int m[3]; + float m[3]; for( int c=0; c<3;c++){ m[c] = (df->data[row-1][3*(col-1)+c] + df->data[row-1][3*col+c] + df->data[row-1][3*(col+1)+c]+ df->data[row] [3*(col-1)+c] + df->data[row] [3*col+c]+ - df->data[row+1][3*(col-1)+c] + df->data[row+1][3*col+c] + df->data[row+1][3*(col+1)+c])/8; + df->data[row+1][3*(col-1)+c] + df->data[row+1][3*col+c] + df->data[row+1][3*(col+1)+c]); } - if( df->data[row][3*col]/threshold > m[0] || df->data[row][3*col+1]/threshold > m[1] || df->data[row][3*col+2]/threshold > m[2]) + if( df->data[row][3*col] > m[0]*threshold || df->data[row][3*col+1] > m[1]*threshold || df->data[row][3*col+2] > m[2]*threshold) badPixels.push_back( badPix(col,row) ); } } @@ -367,7 +377,7 @@ RawImage* DFManager::searchDarkFrame( const Glib::ustring filename ) return df->getRawImage(); return 0; } -std::list *DFManager::getHotPixels ( const Glib::ustring filename ) +std::vector *DFManager::getHotPixels ( const Glib::ustring filename ) { for ( dfList_t::iterator iter = dfList.begin(); iter != dfList.end();iter++ ){ if( iter->second.pathname.compare( filename )==0 ) @@ -375,7 +385,7 @@ std::list *DFManager::getHotPixels ( const Glib::ustring filename ) } return 0; } -std::list *DFManager::getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) +std::vector *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 ){ @@ -408,35 +418,64 @@ int DFManager::scanBadPixelsFile( Glib::ustring filename ) 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) ); - } + std::vector bp; + char line[256]; + if(fgets(line,sizeof(line),file )) { + int x,y; + int offset = 0; + int numparms = sscanf(line,"%d %d",&x,&y); + if( numparms == 1 ) // only one number in first line means, that this is the offset. + offset = x; + else if(numparms == 2) + bp.push_back( badPix(x+offset,y+offset) ); + while( fgets(line,sizeof(line),file ) ){ + if( sscanf(line,"%d %d",&x,&y) == 2 ) + bp.push_back( badPix(x+offset,y+offset) ); + } + } int numPixels = bp.size(); - if( numPixels >0 ) + if( numPixels >0 ) bpList[ makmodel ] = bp; fclose(file); return numPixels; } -std::list *DFManager::getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial) +std::vector *DFManager::getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial) { - std::ostringstream s; - s << mak << " " <verbose ) - printf("Found:%s.badpixels in list\n",s.str().c_str()); - return &(iter->second); - } - if( settings->verbose ) - printf("%s.badpixels not found\n",s.str().c_str()); - return 0; + bpList_t::iterator iter; + bool found = false; + if( !serial.empty() ) { + // search with sreial number first + std::ostringstream s; + s << mak << " " << mod << " " << serial; + iter = bpList.find( s.str() ); + if( iter != bpList.end() ) + found = true; + if( settings->verbose ) + if(found) + printf("%s.badpixels found\n",s.str().c_str()); + else + printf("%s.badpixels not found\n",s.str().c_str()); + + } + if(!found) { + // search without serial number + std::ostringstream s; + s << mak << " " <verbose ) + if(found) + printf("%s.badpixels found\n",s.str().c_str()); + else + printf("%s.badpixels not found\n",s.str().c_str()); + } + if(!found) { + return 0; + } else { + return &(iter->second); + } } // Global variable diff --git a/rtengine/dfmanager.h b/rtengine/dfmanager.h index 3a171b714..11d110cc3 100644 --- a/rtengine/dfmanager.h +++ b/rtengine/dfmanager.h @@ -55,11 +55,11 @@ public: std::string key(){ return key( maker,model,iso,shutter); } RawImage *getRawImage(); - std::list &getHotPixels(); + std::vector &getHotPixels(); protected: RawImage *ri; ///< Dark Frame raw data - std::list badPixels; ///< Extracted hot pixels + std::vector badPixels; ///< Extracted hot pixels void updateBadPixelList( RawImage *df ); void updateRawImage(); @@ -73,13 +73,13 @@ public: 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( 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); + std::vector *getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ); + std::vector *getHotPixels ( const Glib::ustring filename ); + std::vector *getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial); protected: typedef std::multimap dfList_t; - typedef std::map > bpList_t; + typedef std::map > bpList_t; dfList_t dfList; bpList_t bpList; bool initialized; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 79566388b..5069c6ae8 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -155,7 +155,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { rp.bayersensor.ccSteps = 0; rp.xtranssensor.ccSteps = 0; - rp.hotdeadpix_filt = false; + rp.deadPixelFilter = rp.hotPixelFilter = false; } progress ("Applying white balance, color correction & sRGB conversion...",100*readyphase/numofphases); diff --git a/rtengine/procevents.h b/rtengine/procevents.h index f64776e00..1075d2ce6 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -120,7 +120,7 @@ enum ProcEvent { EvLaCurve=95, EvLbCurve=96, EvDemosaicMethod=97, - EvPreProcessHotDeadPixel=98, + EvPreProcessHotPixel=98, EvSaturation=99, EvHSVEqualizerH=100, EvHSVEqualizerS=101, @@ -322,6 +322,7 @@ enum ProcEvent { EvFilmSimulationFilename=294, EvDPDNLCurve=295, EvDPDNsmet=296, + EvPreProcessDeadPixel=297, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index f2856e58d..868d4b94d 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -835,7 +835,8 @@ void ProcParams::setDefaults () { raw.cared = 0; raw.cablue = 0; raw.ca_autocorrect = false; - raw.hotdeadpix_filt = false; + raw.hotPixelFilter = false; + raw.deadPixelFilter = false; raw.hotdeadpix_thresh = 40; exif.clear (); iptc.clear (); @@ -1494,7 +1495,8 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol if (!pedited || pedited->raw.caCorrection) keyFile.set_boolean ("RAW", "CA", raw.ca_autocorrect ); if (!pedited || pedited->raw.caRed) keyFile.set_double ("RAW", "CARed", raw.cared ); if (!pedited || pedited->raw.caBlue) keyFile.set_double ("RAW", "CABlue", raw.cablue ); - if (!pedited || pedited->raw.hotDeadPixelFilter) keyFile.set_boolean ("RAW", "HotDeadPixels", raw.hotdeadpix_filt ); + if (!pedited || pedited->raw.hotPixelFilter) keyFile.set_boolean ("RAW", "HotPixelFilter", raw.hotPixelFilter ); + if (!pedited || pedited->raw.deadPixelFilter) keyFile.set_boolean ("RAW", "DeadPixelFilter", raw.deadPixelFilter ); if (!pedited || pedited->raw.hotDeadPixelThresh) keyFile.set_integer ("RAW", "HotDeadPixelThresh", raw.hotdeadpix_thresh ); if (!pedited || pedited->raw.bayersensor.method) keyFile.set_string ("RAW Bayer", "Method", raw.bayersensor.method ); @@ -2201,7 +2203,11 @@ if (keyFile.has_group ("RAW")) { if (keyFile.has_key ("RAW", "CA")) { raw.ca_autocorrect = keyFile.get_boolean ("RAW", "CA" ); if (pedited) pedited->raw.caCorrection = true; } if (keyFile.has_key ("RAW", "CARed")) { raw.cared = keyFile.get_double ("RAW", "CARed" ); if (pedited) pedited->raw.caRed = true; } if (keyFile.has_key ("RAW", "CABlue")) { raw.cablue = keyFile.get_double ("RAW", "CABlue" ); if (pedited) pedited->raw.caBlue = true; } - if (keyFile.has_key ("RAW", "HotDeadPixels")) { raw.hotdeadpix_filt = keyFile.get_boolean ("RAW", "HotDeadPixels" ); if (pedited) pedited->raw.hotDeadPixelFilter = true; } + // for compatibility to elder pp3 versions + if (keyFile.has_key ("RAW", "HotDeadPixels")) { raw.deadPixelFilter = raw.hotPixelFilter = keyFile.get_boolean ("RAW", "HotDeadPixels" ); if (pedited) pedited->raw.hotPixelFilter = pedited->raw.deadPixelFilter = true; } + if (keyFile.has_key ("RAW", "HotPixelFilter")) { raw.hotPixelFilter = keyFile.get_boolean ("RAW", "HotPixelFilter" ); if (pedited) pedited->raw.hotPixelFilter = true; } + if (keyFile.has_key ("RAW", "DeadPixelFilter")) { raw.deadPixelFilter = keyFile.get_boolean ("RAW", "DeadPixelFilter" ); if (pedited) pedited->raw.deadPixelFilter = true; } + if (keyFile.has_key ("RAW", "HotDeadPixelThresh")) { raw.hotdeadpix_thresh = keyFile.get_integer ("RAW", "HotDeadPixelThresh" ); if (pedited) pedited->raw.hotDeadPixelThresh = true; } if (keyFile.has_key ("RAW", "PreExposure")) { raw.expos =keyFile.get_double("RAW", "PreExposure"); if (pedited) pedited->raw.exPos = true; } if (keyFile.has_key ("RAW", "PrePreserv")) { raw.preser =keyFile.get_double("RAW", "PrePreserv"); if (pedited) pedited->raw.exPreser = true; } @@ -2570,7 +2576,8 @@ bool ProcParams::operator== (const ProcParams& other) { && raw.ca_autocorrect == other.raw.ca_autocorrect && raw.cared == other.raw.cared && raw.cablue == other.raw.cablue - && raw.hotdeadpix_filt == other.raw.hotdeadpix_filt + && raw.hotPixelFilter == other.raw.hotPixelFilter + && raw.deadPixelFilter == other.raw.deadPixelFilter && raw.hotdeadpix_thresh == other.raw.hotdeadpix_thresh && icm.input == other.icm.input && icm.toneCurve == other.icm.toneCurve diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 8bbcdd695..68d16e45a 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -947,7 +947,8 @@ class RAWParams { double expos; double preser; - bool hotdeadpix_filt; + bool hotPixelFilter; + bool deadPixelFilter; int hotdeadpix_thresh; }; diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 809b914bd..441b26450 100755 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -20,7 +20,6 @@ #define __RAWIMAGE_H #include -#include #include "dcraw.h" #include "imageio.h" @@ -28,9 +27,9 @@ namespace rtengine { struct badPix { - int x; - int y; - badPix( int xc, int yc ):x(xc),y(yc){} + uint16_t x; + uint16_t y; + badPix( uint16_t xc, uint16_t yc ):x(xc),y(yc){} }; class PixelsMap{ @@ -66,12 +65,12 @@ public: } // set pixels from a list - int set( std::list &bp) + int set( std::vector &bp) { - int totSet=0; - for(std::list::iterator iter = bp.begin(); iter != bp.end(); iter++,totSet++) + for(std::vector::iterator iter = bp.begin(); iter != bp.end(); ++iter) set( iter->x,iter->y); - return totSet; + + return bp.size(); } void clear(){ @@ -156,6 +155,8 @@ public: int get_thumbBPS(){ return thumb_load_raw ? 16 : 8; } bool get_thumbSwap() const; unsigned get_thumbLength(){ return thumb_length;} + bool zeroIsBad() {return zero_is_bad == 1 ? true : false;} + public: // dcraw functions void scale_colors(){ if(isXtrans()) clearXtransCblack( ); DCraw::scale_colors(); } diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index a14df5ea8..6dccf8b7a 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -456,13 +456,14 @@ void RawImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -/* cfaCleanFromMap: correct raw pixels looking at the bitmap +/* interpolateBadPixels: correct raw pixels looking at the bitmap * takes into consideration if there are multiple bad pixels in the neighborhood */ -int RawImageSource::cfaCleanFromMap( PixelsMap &bitmapBads ) +int RawImageSource::interpolateBadPixels( PixelsMap &bitmapBads ) { - float eps=1.0; + static const float eps=1.f; int counter=0; +#pragma omp parallel for reduction(+:counter) schedule(dynamic,16) for( int row = 2; row < H-2; row++ ){ for(int col = 2; col weighting is 0.70710678 + // For green channel following pixels will be used for interpolation. Pixel to be interpolated is in center. + // 1 means that pixel is used in this step, if itself and his counterpart are not marked bad + // 0 0 0 0 0 + // 0 1 0 1 0 + // 0 0 0 0 0 + // 0 1 0 1 0 + // 0 0 0 0 0 + for( int dx=-1;dx<=1;dx+=2){ + if( bitmapBads.get(col+dx,row-1) || bitmapBads.get(col-dx,row+1)) + continue; + float dirwt = 0.70710678f/( fabsf( rawData[row-1][col+dx]- rawData[row+1][col-dx])+eps); + wtdsum += dirwt * (rawData[row-1][col+dx] + rawData[row+1][col-dx]); + norm += dirwt; + } + } else { + // red and blue channel. Distance to center pixel is sqrt(8) => weighting is 0.35355339 + // For red and blue channel following pixels will be used for interpolation. Pixel to be interpolated is in center. + // 1 means that pixel is used in this step, if itself and his counterpart are not marked bad + // 1 0 0 0 1 + // 0 0 0 0 0 + // 0 0 0 0 0 + // 0 0 0 0 0 + // 1 0 0 0 1 + for( int dx=-2;dx<=2;dx+=4){ + if( bitmapBads.get(col+dx,row-2) || bitmapBads.get(col-dx,row+2)) + continue; + float dirwt = 0.35355339f/( fabsf( rawData[row-2][col+dx]- rawData[row+2][col-dx])+eps); + wtdsum += dirwt * (rawData[row-2][col+dx] + rawData[row+2][col-dx]); norm += dirwt; } } - if (norm > 0.0){ - rawData[row][col]= wtdsum / norm;//gradient weighted average + // channel independent. Distance to center pixel is 2 => weighting is 0.5 + // Additionally for all channel following pixels will be used for interpolation. Pixel to be interpolated is in center. + // 1 means that pixel is used in this step, if itself and his counterpart are not marked bad + // 0 0 1 0 0 + // 0 0 0 0 0 + // 1 0 0 0 1 + // 0 0 0 0 0 + // 0 0 1 0 0 + + // horizontal interpolation + if(!(bitmapBads.get(col-2,row) || bitmapBads.get(col+2,row))) { + float dirwt = 0.5f/( fabsf( rawData[row][col-2]- rawData[row][col+2])+eps); + wtdsum += dirwt * (rawData[row][col-2] + rawData[row][col+2]); + norm += dirwt; + } + + // vertical interpolation + if(!(bitmapBads.get(col,row-2) || bitmapBads.get(col,row+2))) { + float dirwt = 0.5f/( fabsf( rawData[row-2][col]- rawData[row+2][col])+eps); + wtdsum += dirwt * (rawData[row-2][col] + rawData[row+2][col]); + norm += dirwt; + } + + if (LIKELY(norm > 0.f)){ // This means, we found at least one pair of valid pixels in the steps above, likelyhood of this case is about 99.999% + rawData[row][col]= wtdsum / (2.f * norm);//gradient weighted average, Factor of 2.f is an optimization to avoid multiplications in former steps counter++; - } else { - if (tot > 0.1) rawData[row][col] = sum/tot;//backup plan -- simple average + } else { //backup plan -- simple average. Same method for all channels. We could improve this, but it's really unlikely that this case happens + int tot = 0; + float sum = 0; + for( int dy=-2;dy<=2;dy+=2){ + for( int dx=-2;dx<=2;dx+=2){ + if(bitmapBads.get(col+dx,row+dy)) + continue; + sum += rawData[row+dy][col+dx]; + tot++; + } + } + if (tot > 0) { + rawData[row][col] = sum/tot; + counter ++; + } } } } - return counter; + return counter; // Number of interpolated pixels. } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -505,8 +564,10 @@ int RawImageSource::cfaCleanFromMap( PixelsMap &bitmapBads ) * (Taken from Emil Martinec idea) * (Optimized by Ingo Weyrich 2013) */ -int RawImageSource::findHotDeadPixel( PixelsMap &bpMap, float thresh) +int RawImageSource::findHotDeadPixels( PixelsMap &bpMap, float thresh, bool findHotPixels, bool findDeadPixels ) { + float varthresh = (20.0*(thresh/100.0) + 1.0 ); + // counter for dead or hot pixels int counter=0; @@ -528,7 +589,7 @@ int RawImageSource::findHotDeadPixel( PixelsMap &bpMap, float thresh) med3x3(rawData[iprev][jprev],rawData[iprev][j],rawData[iprev][jnext], rawData[i][jprev],rawData[i][j],rawData[i][jnext], rawData[inext][jprev],rawData[inext][j],rawData[inext][jnext],temp); - cfablur[i*W+j] = fabs(rawData[i][j]-temp); + cfablur[i*W+j] = rawData[i][j]-temp; } } #pragma omp for reduction(+:counter) schedule (dynamic,16) @@ -540,16 +601,21 @@ int RawImageSource::findHotDeadPixel( PixelsMap &bpMap, float thresh) for (int cc=0; cc < W; cc++,rrmWpcc++) { //evaluate pixel for heat/death float pixdev = cfablur[rrmWpcc]; + if((!findDeadPixels) && pixdev <= 0) + continue; + if((!findHotPixels) && pixdev >= 0) + continue; + pixdev = fabsf(pixdev); float hfnbrave = -pixdev; int left=max(0,cc-2); int right=min(W-1,cc+2); for (int mm=top; mm<=bottom; mm++) { int mmmWpnn = mm*W+left; for (int nn=left; nn<=right; nn++,mmmWpnn++) { - hfnbrave += cfablur[mmmWpnn]; + hfnbrave += fabsf(cfablur[mmmWpnn]); } } - if (pixdev * ((bottom-top+1)*(right-left+1)-1) > thresh*hfnbrave) { + if (pixdev * ((bottom-top+1)*(right-left+1)-1) > varthresh*hfnbrave) { // mark the pixel as "bad" bpMap.set(cc,rr); counter++; @@ -1015,7 +1081,23 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le if( rid && settings->verbose){ printf( "Subtracting Darkframe:%s\n",rid->get_filename().c_str()); } - //copyOriginalPixels(ri, rid); + + PixelsMap bitmapBads(W,H); + int totBP=0; // Hold count of bad pixels to correct + + if(ri->zeroIsBad()) { // mark all pixels with value zero as bad, has to be called before FF and DF. dcraw sets this flag only for some cameras (mainly Panasonic and Leica) +#pragma omp parallel for reduction(+:totBP) + for(int i=0;idata[i][j] == 0.f) { + bitmapBads.set(j,i); + totBP++; + } + } + if( settings->verbose) { + printf( "%d pixels with value zero marked as bad pixels\n",totBP); + } + } //FLATFIELD start Glib::ustring newFF = raw.ff_file; @@ -1027,20 +1109,18 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le rif = ffm.searchFlatField( idata->getMake(), idata->getModel(),idata->getLens(),idata->getFocalLen(), idata->getFNumber(), idata->getDateTimeAsTS()); } + bool hasFlatField = (rif!=NULL); if( hasFlatField && settings->verbose) { printf( "Flat Field Correction:%s\n",rif->get_filename().c_str()); } + copyOriginalPixels(raw, ri, rid, rif); //FLATFIELD end - - - PixelsMap bitmapBads(W,H); - int totBP=0; // Hold count of bad pixels to correct - // Always correct camera badpixels - std::list *bp = dfm.getBadPixels( ri->get_maker(), ri->get_model(), std::string("") ); + // Always correct camera badpixels from .badpixels file + std::vector *bp = dfm.getBadPixels( ri->get_maker(), ri->get_model(), idata->getSerialNumber() ); if( bp ){ totBP+=bitmapBads.set( *bp ); if( settings->verbose ){ @@ -1061,6 +1141,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } } + scaleColors( 0,0, W, H, raw);//+ + raw parameters for black level(raw.blackxx) // Correct vignetting of lens profile @@ -1081,20 +1162,17 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le defGain = 0.0;//log(initialGain) / log(2.0); - if ( raw.hotdeadpix_filt>0 ) { + if ( raw.hotPixelFilter>0 || raw.deadPixelFilter>0) { if (plistener) { plistener->setProgressStr ("Hot/Dead Pixel Filter..."); plistener->setProgress (0.0); } - float varthresh = (20.0*((float)raw.hotdeadpix_thresh/100.0) + 1.0 ); - int nFound =findHotDeadPixel( bitmapBads, varthresh ); + int nFound = findHotDeadPixels( bitmapBads, raw.hotdeadpix_thresh, raw.hotPixelFilter, raw.deadPixelFilter ); totBP += nFound; if( settings->verbose && nFound>0){ printf( "Correcting %d hot/dead pixels found inside image\n",nFound ); } } - if( totBP ) - cfaCleanFromMap( bitmapBads ); // check if it is an olympus E camera, if yes, compute G channel pre-compensation factors if ( ri->getSensorType()==ST_BAYER && (raw.bayersensor.greenthresh || (((idata->getMake().size()>=7 && idata->getMake().substr(0,7)=="OLYMPUS" && idata->getModel()[0]=='E') || (idata->getMake().size()>=9 && idata->getMake().substr(0,9)=="Panasonic")) && raw.bayersensor.method != RAWParams::BayerSensor::methodstring[ RAWParams::BayerSensor::vng4])) ) { @@ -1136,6 +1214,10 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le green_equilibrate(0.01*(raw.bayersensor.greenthresh)); } + + if( totBP ) + interpolateBadPixels( bitmapBads ); + if ( ri->getSensorType()==ST_BAYER && raw.bayersensor.linenoise >0 ) { if (plistener) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 974e34f22..a5197d03a 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -217,8 +217,8 @@ class RawImageSource : public ImageSource { void ddct8x8s(int isgn, float a[8][8]); void processRawWhitepoint (float expos, float preser); // exposure before interpolation - int cfaCleanFromMap( PixelsMap &bitmapBads ); - int findHotDeadPixel( PixelsMap &bpMap, float thresh); + int interpolateBadPixels( PixelsMap &bitmapBads ); + int findHotDeadPixels( PixelsMap &bpMap, float thresh, bool findHotPixels, bool findDeadPixels ); void cfa_linedn (float linenoiselevel);//Emil's line denoise void cfa_tile_denoise (fftwf_complex * fcfablox, int vblk, int hblk, int numblox_H, int numblox_W, float noisevar, float * rolloff ); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index edf90ba7b..daa48f09a 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -118,7 +118,7 @@ LUMINANCECURVE, // EvLSaturation, LUMINANCECURVE, // EvLaCurve, LUMINANCECURVE, // EvLbCurve, DEMOSAIC, // EvDemosaicMethod -DARKFRAME, // EvPreProcessHotDeadPixel +DARKFRAME, // EvPreProcessHotPixel RGBCURVE, // EvSaturation, RGBCURVE, // EvHSVEqualizerH, RGBCURVE, // EvHSVEqualizerS, @@ -318,8 +318,8 @@ RGBCURVE, //EvFilmSimulationEnabled RGBCURVE, //EvFilmSimulationStrength RGBCURVE, //EvFilmSimulationFilename ALLNORAW, // EvDPDNLCurve -ALLNORAW // EvDPDNsmet - +ALLNORAW, // EvDPDNsmet +DARKFRAME // EvPreProcessDeadPixel }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 6aee8c56c..0126f4aef 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -317,7 +317,8 @@ void ParamsEdited::set (bool v) { raw.caCorrection = v; raw.caBlue = v; raw.caRed = v; - raw.hotDeadPixelFilter = v; + raw.hotPixelFilter = v; + raw.deadPixelFilter = v; raw.hotDeadPixelThresh = v; raw.darkFrame = v; raw.dfAuto = v; @@ -649,7 +650,8 @@ void ParamsEdited::initFrom (const std::vector raw.caCorrection = raw.caCorrection && p.raw.ca_autocorrect == other.raw.ca_autocorrect; raw.caRed = raw.caRed && p.raw.cared == other.raw.cared; raw.caBlue = raw.caBlue && p.raw.cablue == other.raw.cablue; - raw.hotDeadPixelFilter = raw.hotDeadPixelFilter && p.raw.hotdeadpix_filt == other.raw.hotdeadpix_filt; + raw.hotPixelFilter = raw.hotPixelFilter && p.raw.hotPixelFilter == other.raw.hotPixelFilter; + raw.deadPixelFilter = raw.deadPixelFilter && p.raw.deadPixelFilter == other.raw.deadPixelFilter; raw.hotDeadPixelThresh = raw.hotDeadPixelThresh && p.raw.hotdeadpix_thresh == other.raw.hotdeadpix_thresh; raw.darkFrame = raw.darkFrame && p.raw.dark_frame == other.raw.dark_frame; raw.dfAuto = raw.dfAuto && p.raw.df_autoselect == other.raw.df_autoselect; @@ -989,7 +991,8 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (raw.exPos) toEdit.raw.expos = dontforceSet && options.baBehav[ADDSET_RAWEXPOS_LINEAR] ? toEdit.raw.expos + mods.raw.expos : mods.raw.expos; if (raw.exPreser) toEdit.raw.preser = dontforceSet && options.baBehav[ADDSET_RAWEXPOS_PRESER] ? toEdit.raw.preser + mods.raw.preser : mods.raw.preser; - if (raw.hotDeadPixelFilter) toEdit.raw.hotdeadpix_filt = mods.raw.hotdeadpix_filt; + if (raw.hotPixelFilter) toEdit.raw.hotPixelFilter = mods.raw.hotPixelFilter; + if (raw.deadPixelFilter) toEdit.raw.deadPixelFilter = mods.raw.deadPixelFilter; if (raw.hotDeadPixelThresh) toEdit.raw.hotdeadpix_thresh = mods.raw.hotdeadpix_thresh; if (raw.darkFrame) toEdit.raw.dark_frame = mods.raw.dark_frame; if (raw.dfAuto) toEdit.raw.df_autoselect = mods.raw.df_autoselect; @@ -1042,7 +1045,7 @@ bool RAWParamsEdited::XTransSensor::isUnchanged() const { } bool RAWParamsEdited::isUnchanged() const { - return bayersensor.isUnchanged() && xtranssensor.isUnchanged() && caCorrection && caRed && caBlue && hotDeadPixelFilter && hotDeadPixelThresh && darkFrame + return bayersensor.isUnchanged() && xtranssensor.isUnchanged() && caCorrection && caRed && caBlue && hotPixelFilter && deadPixelFilter && hotDeadPixelThresh && darkFrame && dfAuto && ff_file && ff_AutoSelect && ff_BlurRadius && ff_BlurType && exPos && exPreser && ff_AutoClipControl && ff_clipControl; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 4fb6c6617..2d43cfe3d 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -536,7 +536,8 @@ class RAWParamsEdited { bool caCorrection; bool caRed; bool caBlue; - bool hotDeadPixelFilter; + bool hotPixelFilter; + bool deadPixelFilter; bool hotDeadPixelThresh; bool darkFrame; bool dfAuto; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index c4e35af9e..4888e5675 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -97,7 +97,8 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { raw_ca_autocorrect = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAWCACORR_AUTO"))); raw_cared = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAWCACORR_CARED"))); raw_cablue = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAWCACORR_CABLUE"))); - raw_hotdeadpix_filt = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCESS_HOTDEADPIXFILT"))); + raw_hotpix_filt = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCESS_HOTPIXFILT"))); + raw_deadpix_filt = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCESS_DEADPIXFILT"))); raw_linenoise = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCESS_LINEDENOISE"))); raw_greenthresh = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PREPROCESS_GREENEQUIL"))); raw_method = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAW_DMETHOD"))); @@ -190,7 +191,8 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { vboxes[6]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); vboxes[6]->pack_start (*raw_linenoise, Gtk::PACK_SHRINK, 2); vboxes[6]->pack_start (*raw_greenthresh, Gtk::PACK_SHRINK, 2); - vboxes[6]->pack_start (*raw_hotdeadpix_filt, Gtk::PACK_SHRINK, 2); + vboxes[6]->pack_start (*raw_hotpix_filt, Gtk::PACK_SHRINK, 2); + vboxes[6]->pack_start (*raw_deadpix_filt, Gtk::PACK_SHRINK, 2); vboxes[6]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); vboxes[6]->pack_start (*raw_expos, Gtk::PACK_SHRINK, 2); vboxes[6]->pack_start (*raw_preser, Gtk::PACK_SHRINK, 2); @@ -307,7 +309,8 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { raw_ca_autocorrectConn = raw_ca_autocorrect->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); raw_caredConn = raw_cared->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); raw_cablueConn = raw_cablue->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); - raw_hotdeadpix_filtConn = raw_hotdeadpix_filt->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); + raw_hotpix_filtConn = raw_hotpix_filt->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); + raw_deadpix_filtConn = raw_deadpix_filt->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); raw_linenoiseConn = raw_linenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); raw_greenthreshConn = raw_greenthresh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); df_fileConn = df_file->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); @@ -378,7 +381,8 @@ void PartialPasteDlg::rawToggled () { raw_ca_autocorrectConn.block (true); raw_caredConn.block (true); raw_cablueConn.block (true); - raw_hotdeadpix_filtConn.block (true); + raw_hotpix_filtConn.block (true); + raw_deadpix_filtConn.block (true); raw_linenoiseConn.block (true); raw_greenthreshConn.block (true); df_fileConn.block (true); @@ -403,7 +407,8 @@ void PartialPasteDlg::rawToggled () { raw_ca_autocorrect->set_active (raw->get_active ()); raw_cared->set_active (raw->get_active ()); raw_cablue->set_active (raw->get_active ()); - raw_hotdeadpix_filt->set_active (raw->get_active ()); + raw_hotpix_filt->set_active (raw->get_active ()); + raw_deadpix_filt->set_active (raw->get_active ()); raw_linenoise->set_active (raw->get_active ()); raw_greenthresh->set_active (raw->get_active ()); df_file->set_active (raw->get_active ()); @@ -426,7 +431,8 @@ void PartialPasteDlg::rawToggled () { raw_ca_autocorrectConn.block (false); raw_caredConn.block (false); raw_cablueConn.block (false); - raw_hotdeadpix_filtConn.block (false); + raw_hotpix_filtConn.block (false); + raw_deadpix_filtConn.block (false); raw_linenoiseConn.block (false); raw_greenthreshConn.block (false); df_fileConn.block (false); @@ -688,7 +694,9 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param if (!raw_ca_autocorrect->get_active ()) filterPE.raw.caCorrection = falsePE.raw.caCorrection; if (!raw_cared->get_active ()) filterPE.raw.caRed = falsePE.raw.caRed; if (!raw_cablue->get_active ()) filterPE.raw.caBlue = falsePE.raw.caBlue; - if (!raw_hotdeadpix_filt->get_active ()) { filterPE.raw.hotDeadPixelFilter = falsePE.raw.hotDeadPixelFilter; + if (!raw_hotpix_filt->get_active ()) { filterPE.raw.hotPixelFilter = falsePE.raw.hotPixelFilter; + filterPE.raw.hotDeadPixelThresh = falsePE.raw.hotDeadPixelThresh; } + if (!raw_deadpix_filt->get_active ()) { filterPE.raw.deadPixelFilter = falsePE.raw.deadPixelFilter; filterPE.raw.hotDeadPixelThresh = falsePE.raw.hotDeadPixelThresh; } if (!df_file->get_active ()) filterPE.raw.darkFrame = falsePE.raw.darkFrame; if (!df_AutoSelect->get_active ()) filterPE.raw.dfAuto = falsePE.raw.dfAuto; diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index 64750523a..d546b6624 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -94,7 +94,8 @@ class PartialPasteDlg : public Gtk::Dialog { Gtk::CheckButton* raw_ca_autocorrect; Gtk::CheckButton* raw_cared; Gtk::CheckButton* raw_cablue; - Gtk::CheckButton* raw_hotdeadpix_filt; + Gtk::CheckButton* raw_hotpix_filt; + Gtk::CheckButton* raw_deadpix_filt; Gtk::CheckButton* raw_linenoise; Gtk::CheckButton* raw_greenthresh; Gtk::CheckButton* raw_method; @@ -121,7 +122,7 @@ class PartialPasteDlg : public Gtk::Dialog { sigc::connection coarserotConn, finerotConn, cropConn, resizeConn, perspectiveConn, commonTransConn; sigc::connection exifchConn, iptcConn, icmConn, gamcsconn; sigc::connection df_fileConn, df_AutoSelectConn, ff_fileConn, ff_AutoSelectConn, ff_BlurRadiusConn, ff_BlurTypeConn, ff_ClipControlConn; - sigc::connection raw_caredConn, raw_cablueConn, raw_ca_autocorrectConn, raw_hotdeadpix_filtConn, raw_linenoiseConn, raw_greenthreshConn, raw_ccStepsConn, raw_methodConn, raw_dcb_iterationsConn, raw_lmmse_iterationsConn, raw_dcb_enhanceConn, raw_exposConn, raw_preserConn, raw_blackConn; //,raw_all_enhanceConn + sigc::connection raw_caredConn, raw_cablueConn, raw_ca_autocorrectConn, raw_hotpix_filtConn, raw_deadpix_filtConn, raw_linenoiseConn, raw_greenthreshConn, raw_ccStepsConn, raw_methodConn, raw_dcb_iterationsConn, raw_lmmse_iterationsConn, raw_dcb_enhanceConn, raw_exposConn, raw_preserConn, raw_blackConn; //,raw_all_enhanceConn public: PartialPasteDlg (Glib::ustring title); diff --git a/rtgui/preprocess.cc b/rtgui/preprocess.cc index f965f2492..80311a2d2 100644 --- a/rtgui/preprocess.cc +++ b/rtgui/preprocess.cc @@ -26,54 +26,86 @@ using namespace rtengine::procparams; PreProcess::PreProcess () : FoldableToolPanel(this) { - hotDeadPixel = Gtk::manage(new Gtk::CheckButton((M("TP_PREPROCESS_HOTDEADPIXFILT")))); - hotDeadPixel->set_tooltip_markup (M("TP_PREPROCESS_HOTDEADPIXFILT_TOOLTIP")); - - pack_start( *hotDeadPixel, Gtk::PACK_SHRINK, 4); - - hdpixelconn = hotDeadPixel->signal_toggled().connect ( sigc::mem_fun(*this, &PreProcess::hotDeadPixelChanged), true); + + Gtk::HBox* hotdeadPixel = Gtk::manage( new Gtk::HBox () ); + hotdeadPixel->set_spacing(4); + hotPixel = Gtk::manage(new Gtk::CheckButton((M("TP_PREPROCESS_HOTPIXFILT")))); + deadPixel = Gtk::manage(new Gtk::CheckButton((M("TP_PREPROCESS_DEADPIXFILT")))); + + hotPixel->set_tooltip_markup (M("TP_PREPROCESS_HOTPIXFILT_TOOLTIP")); + deadPixel->set_tooltip_markup (M("TP_PREPROCESS_DEADPIXFILT_TOOLTIP")); + + hotdeadPixel->pack_start( *hotPixel, Gtk::PACK_SHRINK); + hotdeadPixel->pack_start( *deadPixel, Gtk::PACK_SHRINK, 0); + pack_start(*hotdeadPixel, Gtk::PACK_SHRINK, 0); +// hotdeadPixel->show(); + hpixelconn = hotPixel->signal_toggled().connect ( sigc::mem_fun(*this, &PreProcess::hotPixelChanged), true); + dpixelconn = deadPixel->signal_toggled().connect ( sigc::mem_fun(*this, &PreProcess::deadPixelChanged), true); } void PreProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { disableListener (); - hdpixelconn.block (true); - + hpixelconn.block (true); + dpixelconn.block (true); if(pedited ){ - hotDeadPixel->set_inconsistent (!pedited->raw.hotDeadPixelFilter); + hotPixel->set_inconsistent (!pedited->raw.hotPixelFilter); + deadPixel->set_inconsistent (!pedited->raw.deadPixelFilter); } - lastHot = pp->raw.hotdeadpix_filt; + lastHot = pp->raw.hotPixelFilter; + lastDead = pp->raw.deadPixelFilter; + hotPixel->set_active (pp->raw.hotPixelFilter); + deadPixel->set_active (pp->raw.deadPixelFilter); - hotDeadPixel->set_active (pp->raw.hotdeadpix_filt); - - hdpixelconn.block (false); + hpixelconn.block (false); + dpixelconn.block (false); enableListener (); } void PreProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) { - pp->raw.hotdeadpix_filt = hotDeadPixel->get_active(); + pp->raw.hotPixelFilter = hotPixel->get_active(); + pp->raw.deadPixelFilter = deadPixel->get_active(); if (pedited) { - pedited->raw.hotDeadPixelFilter = !hotDeadPixel->get_inconsistent(); + pedited->raw.hotPixelFilter = !hotPixel->get_inconsistent(); + pedited->raw.deadPixelFilter = !deadPixel->get_inconsistent(); } } -void PreProcess::hotDeadPixelChanged () +void PreProcess::hotPixelChanged () { if (batchMode) { - if (hotDeadPixel->get_inconsistent()) { - hotDeadPixel->set_inconsistent (false); - hdpixelconn.block (true); - hotDeadPixel->set_active (false); - hdpixelconn.block (false); + if (hotPixel->get_inconsistent()) { + hotPixel->set_inconsistent (false); + hpixelconn.block (true); + hotPixel->set_active (false); + hpixelconn.block (false); } else if (lastHot) - hotDeadPixel->set_inconsistent (true); + hotPixel->set_inconsistent (true); - lastHot = hotDeadPixel->get_active (); + lastHot = hotPixel->get_active (); } if (listener) - listener->panelChanged (EvPreProcessHotDeadPixel, hotDeadPixel->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); + listener->panelChanged (EvPreProcessHotPixel, hotPixel->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); +} + +void PreProcess::deadPixelChanged () +{ + if (batchMode) { + if (deadPixel->get_inconsistent()) { + deadPixel->set_inconsistent (false); + dpixelconn.block (true); + deadPixel->set_active (false); + dpixelconn.block (false); + } + else if (lastDead) + deadPixel->set_inconsistent (true); + + lastDead = deadPixel->get_active (); + } + if (listener) + listener->panelChanged (EvPreProcessDeadPixel, deadPixel->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED")); } diff --git a/rtgui/preprocess.h b/rtgui/preprocess.h index 116cb585e..215f4becb 100644 --- a/rtgui/preprocess.h +++ b/rtgui/preprocess.h @@ -27,10 +27,11 @@ class PreProcess : public ToolParamBlock, /*public AdjusterListener,*/ public FoldableToolPanel { protected: - - Gtk::CheckButton* hotDeadPixel; - bool lastHot; - sigc::connection hdpixelconn; + Gtk::CheckButton* hotPixel; + Gtk::CheckButton* deadPixel; + bool lastHot,lastDead; + sigc::connection hpixelconn; + sigc::connection dpixelconn; public: @@ -41,7 +42,8 @@ class PreProcess : public ToolParamBlock, /*public AdjusterListener,*/ public Fo //void setBatchMode (bool batchMode); //void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); - void hotDeadPixelChanged(); + void hotPixelChanged(); + void deadPixelChanged(); //void adjusterChanged (Adjuster* a, double newval); //void setAdjusterBehavior (bool linedenoiseadd, bool greenequiladd);