From f564394bbce9c66a93e5d0b5b2d7b68131b9bf27 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Thu, 18 Aug 2022 17:00:49 +0200 Subject: [PATCH] dfmanager cleanup (#6211) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Turn `DFManager` into a singleton * PIMPL `DFManager` * Cleanup namespace usage in `dfmanager.cc` * Constify `DFManager` interface * Fix bad `reinterpret_cast` between `std::string` and `Glib::ustring` Co-authored-by: Flössie Co-authored-by: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> --- rtengine/dfmanager.cc | 699 +++++++++++++++++++++---------------- rtengine/dfmanager.h | 91 ++--- rtengine/init.cc | 2 +- rtengine/rawimagesource.cc | 16 +- rtengine/rawimagesource.h | 2 +- rtgui/darkframe.cc | 4 +- rtgui/darkframe.h | 2 +- rtgui/filebrowser.cc | 2 +- rtgui/preferences.cc | 6 +- rtgui/toolpanelcoord.cc | 4 +- rtgui/toolpanelcoord.h | 2 +- 11 files changed, 439 insertions(+), 391 deletions(-) diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index e551c9aad..34215e58c 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -17,28 +17,82 @@ * along with RawTherapee. If not, see . */ -#include -#include +#include #include +#include +#include +#include +#include + #include #include #include "dfmanager.h" -#include "../rtgui/options.h" -#include "rawimage.h" + #include "imagedata.h" +#include "jaggedarray.h" +#include "noncopyable.h" +#include "pixelsmap.h" +#include "rawimage.h" #include "utils.h" -namespace rtengine +#include "../rtgui/options.h" + +namespace { -// *********************** class dfInfo ************************************** +std::string toUppercase(const std::string& string) +{ + return Glib::ustring(string).uppercase(); +} + +class dfInfo final +{ +public: + Glib::ustring pathname; // filename of dark frame + 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 + time_t timestamp; // seconds since 1 Jan 1970 + + + dfInfo(const Glib::ustring &name, const std::string &mak, const std::string &mod, int iso, double shut, time_t t) + : pathname(name), maker(mak), model(mod), iso(iso), shutter(shut), timestamp(t), ri(nullptr) {} + + dfInfo(const dfInfo &o) + : pathname(o.pathname), maker(o.maker), model(o.model), iso(o.iso), shutter(o.shutter), timestamp(o.timestamp), ri(nullptr) {} + ~dfInfo(); + + dfInfo &operator =(const dfInfo &o); + + // Calculate virtual distance between two shots; different model return infinite + double distance(const std::string &mak, const std::string &mod, int iso, double shutter) const; + + static std::string key(const std::string &mak, const std::string &mod, int iso, double shut); + std::string key() const + { + return key(maker, model, iso, shutter); + } + + const rtengine::RawImage* getRawImage(); + const std::vector& getHotPixels(); + +private: + rtengine::RawImage* ri; // Dark Frame raw data + std::vector badPixels; // Extracted hot pixels + + void updateBadPixelList(const rtengine::RawImage* df); + void updateRawImage(); +}; + dfInfo::~dfInfo() { delete ri; } -inline dfInfo& dfInfo::operator =(const dfInfo &o) +inline dfInfo& dfInfo::operator = (const dfInfo &o) { if (this != &o) { pathname = o.pathname; @@ -48,7 +102,7 @@ inline dfInfo& dfInfo::operator =(const dfInfo &o) shutter = o.shutter; timestamp = o.timestamp; - if( ri ) { + if (ri) { delete ri; ri = nullptr; } @@ -57,38 +111,13 @@ inline dfInfo& dfInfo::operator =(const dfInfo &o) return *this; } -bool dfInfo::operator <(const dfInfo &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 dfInfo::key(const std::string &mak, const std::string &mod, int iso, double shut ) +std::string dfInfo::key(const std::string &mak, const std::string &mod, int iso, double shut) { std::ostringstream s; s << mak << " " << mod << " "; s.width(5); s << iso << "ISO "; - s.precision( 2 ); + s.precision(2); s.width(4); s << shut << "s"; return s.str(); @@ -96,115 +125,106 @@ std::string dfInfo::key(const std::string &mak, const std::string &mod, int iso, double dfInfo::distance(const std::string &mak, const std::string &mod, int iso, double shutter) const { - if( this->maker.compare( mak) != 0 ) { + if (this->maker.compare(mak) != 0) { return INFINITY; } - if( this->model.compare( mod) != 0 ) { + if (this->model.compare(mod) != 0) { return INFINITY; } - double dISO = (log(this->iso / 100.) - log(iso / 100.)) / log(2); - double dShutter = (log(this->shutter) - log(shutter)) / log(2); - return sqrt( dISO * dISO + dShutter * dShutter); + const double dISO = (log(this->iso / 100.) - log(iso / 100.)) / log(2); + const double dShutter = (log(this->shutter) - log(shutter)) / log(2); + return std::sqrt(dISO * dISO + dShutter * dShutter); } -RawImage* dfInfo::getRawImage() +const rtengine::RawImage* dfInfo::getRawImage() { - if(ri) { + if (ri) { return ri; } updateRawImage(); - updateBadPixelList( ri ); + updateBadPixelList(ri); return ri; } -std::vector& dfInfo::getHotPixels() +const std::vector& dfInfo::getHotPixels() { - if( !ri ) { + if (!ri) { updateRawImage(); - updateBadPixelList( ri ); + updateBadPixelList(ri); } return badPixels; } + /* 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 dfInfo::updateRawImage() { - typedef unsigned int acc_t; - if( !pathNames.empty() ) { - std::list::iterator iName = pathNames.begin(); - ri = new RawImage(*iName); // First file used also for extra pixels information (width,height, shutter, filters etc.. ) + if (!pathNames.empty()) { + std::list::const_iterator iName = pathNames.begin(); + ri = new rtengine::RawImage(*iName); // First file used also for extra pixels information (width,height, shutter, filters etc.. ) - if( ri->loadRaw(true)) { + if (ri->loadRaw(true)) { delete ri; ri = nullptr; } else { - int H = ri->get_height(); - int W = ri->get_width(); + const int H = ri->get_height(); + const int W = ri->get_width(); ri->compress_image(0); - int rSize = W * ((ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS) ? 1 : 3); - acc_t **acc = new acc_t*[H]; - - for( int row = 0; row < H; row++) { - acc[row] = new acc_t[rSize ]; - } + const int rSize = W * ((ri->getSensorType() == rtengine::ST_BAYER || ri->getSensorType() == rtengine::ST_FUJI_XTRANS) ? 1 : 3); + rtengine::JaggedArray acc(W, H); // copy first image into accumulators - for (int row = 0; row < H; row++) + for (int row = 0; row < H; row++) { for (int col = 0; col < rSize; col++) { acc[row][col] = ri->data[row][col]; } + } int nFiles = 1; // First file data already loaded - for( ++iName; iName != pathNames.end(); ++iName) { - RawImage* temp = new RawImage(*iName); + for (++iName; iName != pathNames.end(); ++iName) { + rtengine::RawImage temp(*iName); - if( !temp->loadRaw(true)) { - temp->compress_image(0); //\ TODO would be better working on original, because is temporary + if (!temp.loadRaw(true)) { + temp.compress_image(0); //\ TODO would be better working on original, because is temporary nFiles++; - if( ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS ) { - for( int row = 0; row < H; row++) { - for( int col = 0; col < W; col++) { - acc[row][col] += temp->data[row][col]; + if (ri->getSensorType() == rtengine::ST_BAYER || ri->getSensorType() == rtengine::ST_FUJI_XTRANS) { + for (int row = 0; row < H; row++) { + for (int col = 0; col < W; col++) { + acc[row][col] += temp.data[row][col]; } } } else { - for( int row = 0; row < H; row++) { - for( int col = 0; col < W; col++) { - acc[row][3 * col + 0] += temp->data[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]; + for (int row = 0; row < H; row++) { + for (int col = 0; col < W; col++) { + acc[row][3 * col + 0] += temp.data[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; } - + const float factor = 1.f / nFiles; for (int row = 0; row < H; row++) { for (int col = 0; col < rSize; col++) { - ri->data[row][col] = acc[row][col] / nFiles; + ri->data[row][col] = acc[row][col] * factor; } - - delete [] acc[row]; } - - delete [] acc; } } else { - ri = new RawImage(pathname); + ri = new rtengine::RawImage(pathname); - if( ri->loadRaw(true)) { + if (ri->loadRaw(true)) { delete ri; ri = nullptr; } else { @@ -213,35 +233,36 @@ void dfInfo::updateRawImage() } } -void dfInfo::updateBadPixelList( RawImage *df ) +void dfInfo::updateBadPixelList(const rtengine::RawImage *df) { - if(!df) { + if (!df) { return; } - const float threshold = 10.f / 8.f; + constexpr float threshold = 10.f / 8.f; - if( df->getSensorType() == ST_BAYER || df->getSensorType() == ST_FUJI_XTRANS ) { - std::vector badPixelsTemp; + if (df->getSensorType() == rtengine::ST_BAYER || df->getSensorType() == rtengine::ST_FUJI_XTRANS) { + std::vector badPixelsTemp; #ifdef _OPENMP #pragma omp parallel #endif { - std::vector badPixelsThread; + std::vector badPixelsThread; #ifdef _OPENMP #pragma omp for nowait #endif - for( int row = 2; row < df->get_height() - 2; row++) - for( int col = 2; col < df->get_width() - 2; col++) { - 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]); + for (int row = 2; row < df->get_height() - 2; ++row) { + for (int col = 2; col < df->get_width() - 2; ++col) { + const 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]; - if( df->data[row][col] > m * threshold ) { + if (df->data[row][col] > m * threshold) { badPixelsThread.emplace_back(col, row); } } + } #ifdef _OPENMP #pragma omp critical @@ -250,48 +271,78 @@ void dfInfo::updateBadPixelList( RawImage *df ) } badPixels.insert(badPixels.end(), badPixelsTemp.begin(), badPixelsTemp.end()); } else { - for( int row = 1; row < df->get_height() - 1; row++) - for( int col = 1; col < df->get_width() - 1; col++) { + for (int row = 1; row < df->get_height() - 1; ++row) { + for (int col = 1; col < df->get_width() - 1; ++col) { 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]); + 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]; } - 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) { + 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.emplace_back(col, row); } } + } } - if( settings->verbose ) { + if (rtengine::settings->verbose) { std::cout << "Extracted " << badPixels.size() << " pixels from darkframe:" << df->get_filename().c_str() << std::endl; } } -// ************************* class DFManager ********************************* +} -void DFManager::init(const Glib::ustring& pathname) +class rtengine::DFManager::Implementation final : + public NonCopyable +{ +public: + void init(const Glib::ustring& pathname); + Glib::ustring getPathname() const + { + return currentPath; + }; + void getStat(int& totFiles, int& totTemplates) const; + const RawImage* searchDarkFrame(const std::string& mak, const std::string& mod, int iso, double shut, time_t t); + const RawImage* searchDarkFrame(const Glib::ustring& filename); + const std::vector* getHotPixels(const std::string& mak, const std::string& mod, int iso, double shut, time_t t); + const std::vector* getHotPixels(const Glib::ustring& filename); + const std::vector* getBadPixels(const std::string& mak, const std::string& mod, const std::string& serial) const; + +private: + typedef std::multimap dfList_t; + typedef std::map > bpList_t; + dfList_t dfList; + bpList_t bpList; + bool initialized; + Glib::ustring currentPath; + dfInfo* addFileInfo(const Glib::ustring &filename, bool pool = true); + dfInfo* find(const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t); + int scanBadPixelsFile(const Glib::ustring &filename); +}; + + +void rtengine::DFManager::Implementation::init(const Glib::ustring& pathname) { if (pathname.empty()) { return; } std::vector names; - auto dir = Gio::File::create_for_path (pathname); + const auto dir = Gio::File::create_for_path(pathname); if (!dir || !dir->query_exists()) { return; } try { - auto enumerator = dir->enumerate_children ("standard::name"); + const auto enumerator = dir->enumerate_children("standard::name"); - while (auto file = enumerator->next_file ()) { - names.emplace_back (Glib::build_filename (pathname, file->get_name ())); + while (const auto file = enumerator->next_file()) { + names.emplace_back(Glib::build_filename(pathname, file->get_name())); } } catch (Glib::Exception&) {} @@ -299,40 +350,40 @@ void DFManager::init(const Glib::ustring& pathname) dfList.clear(); bpList.clear(); - for (size_t i = 0; i < names.size(); i++) { - size_t lastdot = names[i].find_last_of ('.'); + for (const auto &name : names) { + const auto lastdot = name.find_last_of('.'); - if (lastdot != Glib::ustring::npos && names[i].substr(lastdot) == ".badpixels" ) { - int n = scanBadPixelsFile( names[i] ); + if (lastdot != Glib::ustring::npos && name.substr(lastdot) == ".badpixels") { + const int n = scanBadPixelsFile(name); - if( n > 0 && settings->verbose) { - printf("Loaded %s: %d pixels\n", names[i].c_str(), n); + if (n > 0 && settings->verbose) { + printf("Loaded %s: %d pixels\n", name.c_str(), n); } continue; } try { - addFileInfo(names[i]); - } catch( std::exception& e ) {} + addFileInfo(name); + } 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 ) { - dfInfo &i = iter->second; + for (auto &df : dfList) { + dfInfo &i = df.second; - if( !i.pathNames.empty() && !i.pathname.empty() ) { - i.pathNames.push_back( i.pathname ); + if (!i.pathNames.empty() && !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()); + 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()); + printf("%s: MEAN of \n ", i.key().c_str()); - for(std::list::iterator path = i.pathNames.begin(); path != i.pathNames.end(); ++path) { + for (std::list::iterator path = i.pathNames.begin(); path != i.pathNames.end(); ++path) { printf("%s, ", path->c_str()); } @@ -345,9 +396,140 @@ void DFManager::init(const Glib::ustring& pathname) return; } -dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) +void rtengine::DFManager::Implementation::getStat(int& totFiles, int& totTemplates) const { - auto ext = getFileExtension(filename); + totFiles = 0; + totTemplates = 0; + + for (const auto &df : dfList) { + const dfInfo &i = df.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 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 + */ +const rtengine::RawImage* rtengine::DFManager::Implementation::searchDarkFrame(const std::string& mak, const std::string& mod, int iso, double shut, time_t t) +{ + dfInfo* df = find(toUppercase(mak), toUppercase(mod), iso, shut, t); + + if (df) { + return df->getRawImage(); + } else { + return nullptr; + } +} + +const rtengine::RawImage* rtengine::DFManager::Implementation::searchDarkFrame(const Glib::ustring& filename) +{ + for (auto& df : dfList) { + if (df.second.pathname.compare(filename) == 0) { + return df.second.getRawImage(); + } + } + + dfInfo *df = addFileInfo(filename, false); + + if (df) { + return df->getRawImage(); + } + + return nullptr; +} + +const std::vector* rtengine::DFManager::Implementation::getHotPixels(const Glib::ustring& filename) +{ + for (auto& df : dfList) { + if (df.second.pathname.compare(filename) == 0) { + return &df.second.getHotPixels(); + } + } + + return nullptr; +} + +const std::vector* rtengine::DFManager::Implementation::getHotPixels(const std::string& mak, const std::string& mod, int iso, double shut, time_t t) +{ + dfInfo* df = find(toUppercase(mak), toUppercase(mod), iso, shut, t); + + if (df) { + if (settings->verbose) { + if (!df->pathname.empty()) { + printf("Searched hotpixels from %s\n", df->pathname.c_str()); + } else { + if (!df->pathNames.empty()) { + printf("Searched hotpixels from template (first %s)\n", df->pathNames.begin()->c_str()); + } + } + } + + return &df->getHotPixels(); + } else { + return nullptr; + } +} + +const std::vector* rtengine::DFManager::Implementation::getBadPixels(const std::string& mak, const std::string& mod, const std::string& serial) const +{ + bpList_t::const_iterator iter; + bool found = false; + + if (!serial.empty()) { + // search with serial 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 << " " << mod; + 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) { + return nullptr; + } else { + return &(iter->second); + } +} + +dfInfo* rtengine::DFManager::Implementation::addFileInfo(const Glib::ustring& filename, bool pool) +{ + const auto ext = getFileExtension(filename); if (ext.empty() || !options.is_extention_enabled(ext)) { return nullptr; @@ -376,37 +558,34 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) } RawImage ri(filename); - int res = ri.loadRaw(false); // Read information about shot - if (res != 0) { + if (ri.loadRaw(false) != 0) { // Read information about shot return nullptr; } - dfList_t::iterator iter; - - if(!pool) { - dfInfo n(filename, "", "", 0, 0, 0); - iter = dfList.emplace("", n); + if (!pool) { + const dfInfo n(filename, "", "", 0, 0, 0); + auto iter = dfList.emplace("", n); return &(iter->second); } FramesData idata(filename, std::unique_ptr(new RawMetaDataLocation(ri.get_exifBase(), ri.get_ciffBase(), ri.get_ciffLen())), true); /* Files are added in the map, divided by same maker/model,ISO and shutter*/ - std::string key(dfInfo::key(((Glib::ustring)idata.getMake()).uppercase(), ((Glib::ustring)idata.getModel()).uppercase(), idata.getISOSpeed(), idata.getShutterSpeed())); - iter = dfList.find(key); + std::string key(dfInfo::key(toUppercase(idata.getMake()), toUppercase(idata.getModel()), idata.getISOSpeed(), idata.getShutterSpeed())); + auto iter = dfList.find(key); - if(iter == dfList.end()) { - dfInfo n(filename, ((Glib::ustring)idata.getMake()).uppercase(), ((Glib::ustring)idata.getModel()).uppercase(), idata.getISOSpeed(), idata.getShutterSpeed(), idata.getDateTimeAsTS()); + if (iter == dfList.end()) { + dfInfo n(filename, toUppercase(idata.getMake()), toUppercase(idata.getModel()), idata.getISOSpeed(), idata.getShutterSpeed(), idata.getDateTimeAsTS()); iter = dfList.emplace(key, n); } else { while(iter != dfList.end() && iter->second.key() == key && ABS(iter->second.timestamp - idata.getDateTimeAsTS()) > 60 * 60 * 6) { // 6 hour difference ++iter; } - if(iter != dfList.end()) { + if (iter != dfList.end()) { iter->second.pathNames.push_back(filename); } else { - dfInfo n(filename, ((Glib::ustring)idata.getMake()).uppercase(), ((Glib::ustring)idata.getModel()).uppercase(), idata.getISOSpeed(), idata.getShutterSpeed(), idata.getDateTimeAsTS()); + dfInfo n(filename, toUppercase(idata.getMake()), toUppercase(idata.getModel()), idata.getISOSpeed(), idata.getShutterSpeed(), idata.getDateTimeAsTS()); iter = dfList.emplace(key, n); } } @@ -418,44 +597,23 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) return nullptr; } -void DFManager::getStat( int &totFiles, int &totTemplates) +dfInfo* rtengine::DFManager::Implementation::find(const std::string& mak, const std::string& mod, int isospeed, double shut, time_t t) { - totFiles = 0; - totTemplates = 0; - - for( dfList_t::iterator iter = dfList.begin(); iter != dfList.end(); ++iter ) { - dfInfo &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 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 ) -{ - if( dfList.empty() ) { + if (dfList.empty()) { return nullptr; } - std::string key( dfInfo::key(mak, mod, isospeed, shut) ); - dfList_t::iterator iter = dfList.find( key ); + const std::string key(dfInfo::key(mak, mod, isospeed, shut)); + dfList_t::iterator iter = dfList.find(key); - if( iter != dfList.end() ) { + if (iter != dfList.end()) { dfList_t::iterator bestMatch = iter; time_t bestDeltaTime = ABS(iter->second.timestamp - t); - for(++iter; iter != dfList.end() && !key.compare( iter->second.key() ); ++iter ) { - time_t d = ABS(iter->second.timestamp - t ); + for (++iter; iter != dfList.end() && !key.compare(iter->second.key()); ++iter) { + const time_t d = ABS(iter->second.timestamp - t); - if( d < bestDeltaTime ) { + if (d < bestDeltaTime) { bestMatch = iter; bestDeltaTime = d; } @@ -465,12 +623,12 @@ dfInfo* DFManager::find( const std::string &mak, const std::string &mod, int iso } else { iter = dfList.begin(); dfList_t::iterator bestMatch = iter; - double bestD = iter->second.distance( mak, mod, isospeed, shut ); + double bestD = iter->second.distance(mak, mod, isospeed, shut); - for( ++iter; iter != dfList.end(); ++iter ) { - double d = iter->second.distance( mak, mod, isospeed, shut ); + for (++iter; iter != dfList.end(); ++iter) { + const double d = iter->second.distance(mak, mod, isospeed, shut); - if( d < bestD ) { + if (d < bestD) { bestD = d; bestMatch = iter; } @@ -480,170 +638,107 @@ dfInfo* DFManager::find( const std::string &mak, const std::string &mod, int iso } } -RawImage* DFManager::searchDarkFrame( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) -{ - dfInfo *df = find( ((Glib::ustring)mak).uppercase(), ((Glib::ustring)mod).uppercase(), iso, shut, t ); - - if( df ) { - return df->getRawImage(); - } else { - return nullptr; - } -} - -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, false ); - - if(df) { - return df->getRawImage(); - } - - return nullptr; -} -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 ) { - return &iter->second.getHotPixels(); - } - } - - return nullptr; -} -std::vector *DFManager::getHotPixels ( const std::string &mak, const std::string &mod, int iso, double shut, time_t t ) -{ - dfInfo *df = find( ((Glib::ustring)mak).uppercase(), ((Glib::ustring)mod).uppercase(), iso, shut, t ); - - if( df ) { - if( settings->verbose ) { - if( !df->pathname.empty() ) { - printf( "Searched hotpixels from %s\n", df->pathname.c_str()); - } else { - if( !df->pathNames.empty() ) { - printf( "Searched hotpixels from template (first %s)\n", df->pathNames.begin()->c_str()); - } - } - } - - return &df->getHotPixels(); - } else { - return nullptr; - } -} - -int DFManager::scanBadPixelsFile( Glib::ustring filename ) +int rtengine::DFManager::Implementation::scanBadPixelsFile(const Glib::ustring& filename) { FILE *file = ::fopen( filename.c_str(), "r" ); - if( !file ) { - return false; + if (!file) { + return 0; } - size_t lastdot = filename.find_last_of ('.'); - size_t dirpos1 = filename.find_last_of ('/'); - size_t dirpos2 = filename.find_last_of ('\\'); + const auto lastdot = filename.find_last_of('.'); + auto dirpos1 = filename.find_last_of('/'); + auto dirpos2 = filename.find_last_of('\\'); - if( dirpos1 == Glib::ustring::npos && dirpos2 == Glib::ustring::npos ) { + if (dirpos1 == Glib::ustring::npos && dirpos2 == Glib::ustring::npos) { dirpos1 = 0; - } else if( dirpos1 != Glib::ustring::npos && dirpos2 != Glib::ustring::npos ) { + } else if (dirpos1 != Glib::ustring::npos && dirpos2 != Glib::ustring::npos) { dirpos1 = (dirpos1 > dirpos2 ? dirpos1 : dirpos2); - } else if( dirpos1 == Glib::ustring::npos ) { + } else if (dirpos1 == Glib::ustring::npos) { dirpos1 = dirpos2; } - std::string makmodel(filename, dirpos1 + 1, lastdot - (dirpos1 + 1) ); + const std::string makmodel(filename, dirpos1 + 1, lastdot - (dirpos1 + 1)); std::vector bp; char line[256]; - if(fgets(line, sizeof(line), file )) { + 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. + if (numparms == 1) { // only one number in first line means, that this is the offset. offset = x; - } else if(numparms == 2) { + } else if (numparms == 2) { bp.emplace_back(x + offset, y + offset); } - while( fgets(line, sizeof(line), file ) ) { - if( sscanf(line, "%d %d", &x, &y) == 2 ) { + while(fgets(line, sizeof(line), file)) { + if (sscanf(line, "%d %d", &x, &y) == 2) { bp.emplace_back(x + offset, y + offset); } } } - int numPixels = bp.size(); + const int numPixels = bp.size(); - if( numPixels > 0 ) { - bpList[ makmodel ] = bp; + if (numPixels > 0) { + bpList[makmodel] = bp; } fclose(file); return numPixels; } -std::vector *DFManager::getBadPixels ( const std::string &mak, const std::string &mod, const std::string &serial) +rtengine::DFManager& rtengine::DFManager::getInstance() { - bpList_t::iterator iter; - bool found = false; - - if( !serial.empty() ) { - // search with serial 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 << " " << mod; - 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) { - return nullptr; - } else { - return &(iter->second); - } + static DFManager instance; + return instance; } -// Global variable -DFManager dfm; - - +void rtengine::DFManager::init(const Glib::ustring& pathname) +{ + implementation->init(pathname); } +Glib::ustring rtengine::DFManager::getPathname() const +{ + return implementation->getPathname(); +} + +void rtengine::DFManager::getStat(int& totFiles, int& totTemplates) const +{ + implementation->getStat(totFiles, totTemplates); +} + +const rtengine::RawImage* rtengine::DFManager::searchDarkFrame(const std::string& mak, const std::string& mod, int iso, double shut, time_t t) +{ + return implementation->searchDarkFrame(mak, mod, iso, shut, t); +} + +const rtengine::RawImage* rtengine::DFManager::searchDarkFrame(const Glib::ustring& filename) +{ + return implementation->searchDarkFrame(filename); +} + +const std::vector* rtengine::DFManager::getHotPixels(const std::string& mak, const std::string& mod, int iso, double shut, time_t t) +{ + return implementation->getHotPixels(mak, mod, iso, shut, t); +} + +const std::vector* rtengine::DFManager::getHotPixels(const Glib::ustring& filename) +{ + return implementation->getHotPixels(filename); +} + +const std::vector* rtengine::DFManager::getBadPixels(const std::string& mak, const std::string& mod, const std::string& serial) const +{ + return implementation->getBadPixels(mak, mod, serial); +} + +rtengine::DFManager::DFManager() : + implementation(new Implementation) +{ +} + +rtengine::DFManager::~DFManager() = default; diff --git a/rtengine/dfmanager.h b/rtengine/dfmanager.h index b23981ffb..01ee7479a 100644 --- a/rtengine/dfmanager.h +++ b/rtengine/dfmanager.h @@ -18,89 +18,40 @@ */ #pragma once -#include -#include -#include +#include #include +#include #include -#include "pixelsmap.h" - namespace rtengine { +struct badPix; + class RawImage; -class dfInfo final -{ -public: - - Glib::ustring pathname; // filename of dark frame - 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 - time_t timestamp; ///< seconds since 1 Jan 1970 - - - dfInfo(const Glib::ustring &name, const std::string &mak, const std::string &mod, int iso, double shut, time_t t) - : pathname(name), maker(mak), model(mod), iso(iso), shutter(shut), timestamp(t), ri(nullptr) {} - - dfInfo( const dfInfo &o) - : pathname(o.pathname), maker(o.maker), model(o.model), iso(o.iso), shutter(o.shutter), timestamp(o.timestamp), ri(nullptr) {} - ~dfInfo(); - - dfInfo &operator =(const dfInfo &o); - bool operator <(const dfInfo &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) const; - - static std::string key(const std::string &mak, const std::string &mod, int iso, double shut ); - std::string key() - { - return key( maker, model, iso, shutter); - } - - RawImage *getRawImage(); - std::vector &getHotPixels(); - -protected: - RawImage *ri; ///< Dark Frame raw data - std::vector badPixels; ///< Extracted hot pixels - - void updateBadPixelList( RawImage *df ); - void updateRawImage(); -}; class DFManager final { public: - void init(const Glib::ustring &pathname); - 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( const Glib::ustring filename ); - 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); + static DFManager& getInstance(); -protected: - typedef std::multimap dfList_t; - typedef std::map > bpList_t; - dfList_t dfList; - bpList_t bpList; - bool initialized; - Glib::ustring currentPath; - dfInfo *addFileInfo(const Glib::ustring &filename, bool pool = true ); - dfInfo *find( const std::string &mak, const std::string &mod, int isospeed, double shut, time_t t ); - int scanBadPixelsFile( Glib::ustring filename ); + void init(const Glib::ustring& pathname); + Glib::ustring getPathname() const; + void getStat(int& totFiles, int& totTemplates) const; + const RawImage* searchDarkFrame(const std::string& mak, const std::string& mod, int iso, double shut, time_t t); + const RawImage* searchDarkFrame(const Glib::ustring& filename); + const std::vector* getHotPixels(const std::string& mak, const std::string& mod, int iso, double shut, time_t t); + const std::vector* getHotPixels(const Glib::ustring& filename); + const std::vector* getBadPixels(const std::string& mak, const std::string& mod, const std::string& serial) const; + +private: + DFManager(); + ~DFManager(); + + class Implementation; + + const std::unique_ptr implementation; }; -extern DFManager dfm; - } diff --git a/rtengine/init.cc b/rtengine/init.cc index 1a00f7ff6..ff29c3476 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -92,7 +92,7 @@ int init (const Settings* s, const Glib::ustring& baseDir, const Glib::ustring& #pragma omp section #endif { - dfm.init(s->darkFramesPath); + DFManager::getInstance().init(s->darkFramesPath); } #ifdef _OPENMP #pragma omp section diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 57b8f632c..48d7b0904 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -34,6 +34,7 @@ #include "median.h" #include "mytime.h" #include "pdaflinesfilter.h" +#include "pixelsmap.h" #include "procparams.h" #include "rawimage.h" #include "rawimagesource_i.h" @@ -41,6 +42,7 @@ #include "rt_math.h" #include "rtengine.h" #include "rtlensfun.h" + #include "../rtgui/options.h" #define BENCHMARK @@ -1307,14 +1309,14 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le Glib::ustring newDF = raw.dark_frame; - RawImage *rid = nullptr; + const RawImage* rid = nullptr; if (!raw.df_autoselect) { if (!raw.dark_frame.empty()) { - rid = dfm.searchDarkFrame(raw.dark_frame); + rid = DFManager::getInstance().searchDarkFrame(raw.dark_frame); } } else { - rid = dfm.searchDarkFrame(idata->getMake(), idata->getModel(), idata->getISOSpeed(), idata->getShutterSpeed(), idata->getDateTimeAsTS()); + rid = DFManager::getInstance().searchDarkFrame(idata->getMake(), idata->getModel(), idata->getISOSpeed(), idata->getShutterSpeed(), idata->getDateTimeAsTS()); } if (rid && settings->verbose) { @@ -1387,7 +1389,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le // Always correct camera badpixels from .badpixels file - std::vector *bp = dfm.getBadPixels(ri->get_maker(), ri->get_model(), idata->getSerialNumber()); + const std::vector *bp = DFManager::getInstance().getBadPixels(ri->get_maker(), ri->get_model(), idata->getSerialNumber()); if (bp) { if (!bitmapBads) { @@ -1405,9 +1407,9 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le bp = nullptr; if (raw.df_autoselect) { - bp = dfm.getHotPixels(idata->getMake(), idata->getModel(), idata->getISOSpeed(), idata->getShutterSpeed(), idata->getDateTimeAsTS()); + bp = DFManager::getInstance().getHotPixels(idata->getMake(), idata->getModel(), idata->getISOSpeed(), idata->getShutterSpeed(), idata->getDateTimeAsTS()); } else if (!raw.dark_frame.empty()) { - bp = dfm.getHotPixels(raw.dark_frame); + bp = DFManager::getInstance().getHotPixels(raw.dark_frame); } if (bp) { @@ -2453,7 +2455,7 @@ void RawImageSource::HLRecovery_Global(const ToneCurveParams &hrp) /* Copy original pixel data and * subtract dark frame (if present) from current image and apply flat field correction (if present) */ -void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, RawImage *riDark, RawImage *riFlatFile, array2D &rawData) +void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, const RawImage *riDark, RawImage *riFlatFile, array2D &rawData) { const auto tmpfilters = ri->get_filters(); ri->set_filters(ri->prefilters); // we need 4 blacks for bayer processing diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 16677b1da..41a400dd9 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -138,7 +138,7 @@ public: } void processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, array2D &rawData, const float black[4]); - void copyOriginalPixels(const procparams::RAWParams &raw, RawImage *ri, RawImage *riDark, RawImage *riFlatFile, array2D &rawData ); + void copyOriginalPixels(const procparams::RAWParams &raw, RawImage *ri, const RawImage *riDark, RawImage *riFlatFile, array2D &rawData ); void scaleColors (int winx, int winy, int winw, int winh, const procparams::RAWParams &raw, array2D &rawData); // raw for cblack void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) override; void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) override; diff --git a/rtgui/darkframe.cc b/rtgui/darkframe.cc index b6b1201a7..5c71d9918 100644 --- a/rtgui/darkframe.cc +++ b/rtgui/darkframe.cc @@ -97,7 +97,7 @@ void DarkFrame::read(const rtengine::procparams::ProcParams* pp, const ParamsEdi if( pp->raw.df_autoselect && dfp && !multiImage) { // retrieve the auto-selected df filename - rtengine::RawImage *img = dfp->getDF(); + const rtengine::RawImage *img = dfp->getDF(); if( img ) { dfInfo->set_text( Glib::ustring::compose("%1: %2ISO %3s", Glib::path_get_basename(img->get_filename()), img->get_ISOspeed(), img->get_shutter()) ); @@ -179,7 +179,7 @@ void DarkFrame::dfAutoChanged() if(dfAuto->get_active() && dfp && !batchMode) { // retrieve the auto-selected df filename - rtengine::RawImage *img = dfp->getDF(); + const rtengine::RawImage *img = dfp->getDF(); if( img ) { dfInfo->set_text( Glib::ustring::compose("%1: %2ISO %3s", Glib::path_get_basename(img->get_filename()), img->get_ISOspeed(), img->get_shutter()) ); diff --git a/rtgui/darkframe.h b/rtgui/darkframe.h index 58e8b4842..cbd7816d6 100644 --- a/rtgui/darkframe.h +++ b/rtgui/darkframe.h @@ -36,7 +36,7 @@ class DFProvider { public: virtual ~DFProvider() = default; - virtual rtengine::RawImage* getDF() = 0; + virtual const rtengine::RawImage* getDF() = 0; virtual Glib::ustring GetCurrentImageFilePath() = 0; // add other info here }; diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 97e724174..66c84d86e 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -875,7 +875,7 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) } // Reinit cache - rtengine::dfm.init( options.rtSettings.darkFramesPath ); + rtengine::DFManager::getInstance().init( options.rtSettings.darkFramesPath ); } else { // Target directory creation failed, we clear the darkFramesPath setting options.rtSettings.darkFramesPath.clear(); diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index c6c2eb61b..c44ad11ca 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -2641,8 +2641,8 @@ void Preferences::darkFrameChanged() { //Glib::ustring s(darkFrameDir->get_filename()); Glib::ustring s(darkFrameDir->get_current_folder()); - //if( s.compare( rtengine::dfm.getPathname()) !=0 ){ - rtengine::dfm.init(s); + //if( s.compare( rtengine::DFManager::getInstance().getPathname()) !=0 ){ + rtengine::DFManager::getInstance().init(s); updateDFinfos(); //} } @@ -2660,7 +2660,7 @@ void Preferences::flatFieldChanged() void Preferences::updateDFinfos() { int t1, t2; - rtengine::dfm.getStat(t1, t2); + rtengine::DFManager::getInstance().getStat(t1, t2); Glib::ustring s = Glib::ustring::compose("%1: %2 %3, %4 %5", M("PREFERENCES_DARKFRAMEFOUND"), t1, M("PREFERENCES_DARKFRAMESHOTS"), t2, M("PREFERENCES_DARKFRAMETEMPLATES")); dfLabel->set_text(s); } diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 9099f5620..54102a2e1 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -944,7 +944,7 @@ void ToolPanelCoordinator::autoCropRequested() crop->cropManipReady(); } -rtengine::RawImage* ToolPanelCoordinator::getDF() +const rtengine::RawImage* ToolPanelCoordinator::getDF() { if (!ipc) { return nullptr; @@ -959,7 +959,7 @@ rtengine::RawImage* ToolPanelCoordinator::getDF() std::string model(imd->getModel()); time_t timestamp = imd->getDateTimeAsTS(); - return rtengine::dfm.searchDarkFrame(maker, model, iso, shutter, timestamp); + return rtengine::DFManager::getInstance().searchDarkFrame(maker, model, iso, shutter, timestamp); } return nullptr; diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 13686d6e3..65e2f1e8f 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -307,7 +307,7 @@ public: } //DFProvider interface - rtengine::RawImage* getDF() override; + const rtengine::RawImage* getDF() override; //FFProvider interface rtengine::RawImage* getFF() override;