"Fossies" - the Fresh Open Source Software Archive

Member "rawtherapee-5.7/rtengine/ffmanager.cc" (10 Sep 2019, 13766 Bytes) of package /linux/misc/rawtherapee-5.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ffmanager.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.6_vs_5.7.

    1 /*
    2  *  This file is part of RawTherapee.
    3  *
    4  *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
    5  *
    6  *  RawTherapee is free software: you can redistribute it and/or modify
    7  *  it under the terms of the GNU General Public License as published by
    8  *  the Free Software Foundation, either version 3 of the License, or
    9  *  (at your option) any later version.
   10  *
   11  *  RawTherapee is distributed in the hope that it will be useful,
   12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  *  GNU General Public License for more details.
   15  *
   16  *  You should have received a copy of the GNU General Public License
   17  *  along with RawTherapee.  If not, see <https://www.gnu.org/licenses/>.
   18  */
   19 #include "ffmanager.h"
   20 #include "../rtgui/options.h"
   21 #include "rawimage.h"
   22 #include "imagedata.h"
   23 #include "median.h"
   24 #include "utils.h"
   25 
   26 namespace rtengine
   27 {
   28 
   29 extern const Settings* settings;
   30 
   31 // *********************** class ffInfo **************************************
   32 
   33 inline ffInfo& ffInfo::operator =(const ffInfo &o)
   34 {
   35     if (this != &o) {
   36         pathname = o.pathname;
   37         maker = o.maker;
   38         model = o.model;
   39         lens = o.lens;
   40         focallength = o.focallength;
   41         timestamp = o.timestamp;
   42         aperture = o.aperture;
   43 
   44         if( ri ) {
   45             delete ri;
   46             ri = nullptr;
   47         }
   48     }
   49 
   50     return *this;
   51 }
   52 
   53 bool ffInfo::operator <(const ffInfo &e2) const
   54 {
   55     if( this->maker.compare( e2.maker) >= 0 ) {
   56         return false;
   57     }
   58 
   59     if( this->model.compare( e2.model) >= 0 ) {
   60         return false;
   61     }
   62 
   63     if( this->lens.compare( e2.lens) >= 0 ) {
   64         return false;
   65     }
   66 
   67     if( this->focallength >= e2.focallength ) {
   68         return false;
   69     }
   70 
   71     if( this->timestamp >= e2.timestamp ) {
   72         return false;
   73     }
   74 
   75     return true;
   76 }
   77 
   78 std::string ffInfo::key(const std::string &mak, const std::string &mod, const std::string &len, double focal, double apert )
   79 {
   80     std::ostringstream s;
   81     s << mak << " " << mod << " ";
   82     s.width(5);
   83     s << len << " ";
   84     s.precision( 2 );
   85     s.width(4);
   86     s << focal << "mm F" << apert;
   87     return s.str();
   88 }
   89 
   90 double ffInfo::distance(const std::string &mak, const std::string &mod, const std::string &len, double focallength, double aperture) const
   91 {
   92     if( this->maker.compare( mak) != 0 ) {
   93         return INFINITY;
   94     }
   95 
   96     if( this->model.compare( mod) != 0 ) {
   97         return INFINITY;
   98     }
   99 
  100     if( this->lens.compare( len) != 0 ) {
  101         return INFINITY;
  102     }
  103 
  104     double dAperture = 2 * (log(this->aperture) - log(aperture)) / log(2); //more important for vignette
  105     double dfocallength = (log(this->focallength / 100.) - log(focallength / 100.)) / log(2); //more important for PRNU
  106 
  107     return sqrt( dfocallength * dfocallength + dAperture * dAperture);
  108 }
  109 
  110 RawImage* ffInfo::getRawImage()
  111 {
  112     if(ri) {
  113         return ri;
  114     }
  115 
  116     updateRawImage();
  117 
  118     return ri;
  119 }
  120 
  121 /* updateRawImage() load into ri the actual pixel data from pathname if there is a single shot
  122  * otherwise load each file from the pathNames list and extract a template from the media;
  123  * the first file is used also for reading all information other than pixels
  124  */
  125 void ffInfo::updateRawImage()
  126 {
  127     typedef unsigned int acc_t;
  128 
  129     // averaging of flatfields if more than one is found matching the same key.
  130     // this may not be necessary, as flatfield is further blurred before being applied to the processed image.
  131     if( !pathNames.empty() ) {
  132         std::list<Glib::ustring>::iterator iName = pathNames.begin();
  133         ri = new RawImage(*iName); // First file used also for extra pixels information (width, height, shutter, filters etc.. )
  134         if( ri->loadRaw(true)) {
  135             delete ri;
  136             ri = nullptr;
  137         } else {
  138             int H = ri->get_height();
  139             int W = ri->get_width();
  140             ri->compress_image(0);
  141             int rSize = W * ((ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS || ri->get_colors() == 1) ? 1 : 3);
  142             acc_t **acc = new acc_t*[H];
  143 
  144             for( int row = 0; row < H; row++) {
  145                 acc[row] = new acc_t[rSize ];
  146             }
  147 
  148             // copy first image into accumulators
  149             for (int row = 0; row < H; row++)
  150                 for (int col = 0; col < rSize; col++) {
  151                     acc[row][col] = ri->data[row][col];
  152                 }
  153 
  154             int nFiles = 1; // First file data already loaded
  155 
  156             for( ++iName; iName != pathNames.end(); ++iName) {
  157                 RawImage* temp = new RawImage(*iName);
  158 
  159                 if( !temp->loadRaw(true)) {
  160                     temp->compress_image(0);     //\ TODO would be better working on original, because is temporary
  161                     nFiles++;
  162 
  163                     if( ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS || ri->get_colors() == 1 ) {
  164                         for( int row = 0; row < H; row++) {
  165                             for( int col = 0; col < W; col++) {
  166                                 acc[row][col] += temp->data[row][col];
  167                             }
  168                         }
  169                     } else {
  170                         for( int row = 0; row < H; row++) {
  171                             for( int col = 0; col < W; col++) {
  172                                 acc[row][3 * col + 0] += temp->data[row][3 * col + 0];
  173                                 acc[row][3 * col + 1] += temp->data[row][3 * col + 1];
  174                                 acc[row][3 * col + 2] += temp->data[row][3 * col + 2];
  175                             }
  176                         }
  177                     }
  178                 }
  179 
  180                 delete temp;
  181             }
  182 
  183             for (int row = 0; row < H; row++) {
  184                 for (int col = 0; col < rSize; col++) {
  185                     ri->data[row][col] = acc[row][col] / nFiles;
  186                 }
  187 
  188                 delete [] acc[row];
  189             }
  190 
  191             delete [] acc;
  192         }
  193     } else {
  194         ri = new RawImage(pathname);
  195         if( ri->loadRaw(true)) {
  196             delete ri;
  197             ri = nullptr;
  198         } else {
  199             ri->compress_image(0);
  200         }
  201     }
  202 
  203     if(ri) {
  204         // apply median to avoid this step being executed each time a flat field gets applied
  205         int H = ri->get_height();
  206         int W = ri->get_width();
  207         float *cfatmp = (float (*)) malloc (H * W * sizeof * cfatmp);
  208 
  209 #ifdef _OPENMP
  210         #pragma omp parallel for schedule(dynamic,16)
  211 #endif
  212 
  213         for (int i = 0; i < H; i++) {
  214             int iprev = i < 2 ? i + 2 : i - 2;
  215             int inext = i > H - 3 ? i - 2 : i + 2;
  216 
  217             for (int j = 0; j < W; j++) {
  218                 int jprev = j < 2 ? j + 2 : j - 2;
  219                 int jnext = j > W - 3 ? j - 2 : j + 2;
  220 
  221                 cfatmp[i * W + j] = median(ri->data[iprev][j], ri->data[i][jprev], ri->data[i][j], ri->data[i][jnext], ri->data[inext][j]);
  222             }
  223         }
  224 
  225         memcpy(ri->data[0], cfatmp, W * H * sizeof(float));
  226 
  227         free (cfatmp);
  228 
  229     }
  230 }
  231 
  232 // ************************* class FFManager *********************************
  233 
  234 void FFManager::init(const Glib::ustring& pathname)
  235 {
  236     if (pathname.empty()) {
  237         return;
  238     }
  239     std::vector<Glib::ustring> names;
  240 
  241     auto dir = Gio::File::create_for_path (pathname);
  242 
  243     if (!dir || !dir->query_exists()) {
  244         return;
  245     }
  246 
  247     try {
  248 
  249         auto enumerator = dir->enumerate_children ("standard::name");
  250 
  251         while (auto file = enumerator->next_file ()) {
  252             names.emplace_back (Glib::build_filename (pathname, file->get_name ()));
  253         }
  254 
  255     } catch (Glib::Exception&) {}
  256 
  257     ffList.clear();
  258 
  259     for (size_t i = 0; i < names.size(); i++) {
  260         try {
  261             addFileInfo(names[i]);
  262         } catch( std::exception& e ) {}
  263     }
  264 
  265     // Where multiple shots exist for same group, move filename to list
  266     for( ffList_t::iterator iter = ffList.begin(); iter != ffList.end(); ++iter ) {
  267         ffInfo &i = iter->second;
  268 
  269         if( !i.pathNames.empty() && !i.pathname.empty() ) {
  270             i.pathNames.push_back( i.pathname );
  271             i.pathname.clear();
  272         }
  273 
  274         if( settings->verbose ) {
  275             if( !i.pathname.empty() ) {
  276                 printf( "%s:  %s\n", i.key().c_str(), i.pathname.c_str());
  277             } else {
  278                 printf( "%s: MEAN of \n    ", i.key().c_str());
  279 
  280                 for(std::list<Glib::ustring>::iterator path = i.pathNames.begin(); path != i.pathNames.end(); ++path) {
  281                     printf("%s, ", path->c_str());
  282                 }
  283 
  284                 printf("\n");
  285             }
  286         }
  287     }
  288 
  289     currentPath = pathname;
  290     return;
  291 }
  292 
  293 ffInfo* FFManager::addFileInfo (const Glib::ustring& filename, bool pool)
  294 {
  295     auto ext = getFileExtension(filename);
  296 
  297     if (ext.empty() || !options.is_extention_enabled(ext)) {
  298         return nullptr;
  299     }
  300 
  301     auto file = Gio::File::create_for_path(filename);
  302 
  303     if (!file ) {
  304         return nullptr;
  305     }
  306 
  307     if (!file->query_exists()) {
  308         return nullptr;
  309     }
  310 
  311     try {
  312 
  313         auto info = file->query_info("standard::name,standard::type,standard::is-hidden");
  314 
  315         if (!info || info->get_file_type() == Gio::FILE_TYPE_DIRECTORY) {
  316             return nullptr;
  317         }
  318 
  319         if (!options.fbShowHidden && info->is_hidden()) {
  320             return nullptr;
  321         }
  322 
  323         RawImage ri(filename);
  324         int res = ri.loadRaw(false); // Read information about shot
  325 
  326         if (res != 0) {
  327             return nullptr;
  328         }
  329 
  330         ffList_t::iterator iter;
  331 
  332         if(!pool) {
  333             ffInfo n(filename, "", "", "", 0, 0, 0);
  334             iter = ffList.emplace("", n);
  335             return &(iter->second);
  336         }
  337 
  338         FramesData idata(filename, std::unique_ptr<RawMetaDataLocation>(new RawMetaDataLocation(ri.get_exifBase(), ri.get_ciffBase(), ri.get_ciffLen())), true);
  339         /* Files are added in the map, divided by same maker/model,lens and aperture*/
  340         std::string key(ffInfo::key(idata.getMake(), idata.getModel(), idata.getLens(), idata.getFocalLen(), idata.getFNumber()));
  341         iter = ffList.find(key);
  342 
  343         if(iter == ffList.end()) {
  344             ffInfo n(filename, idata.getMake(), idata.getModel(), idata.getLens(), idata.getFocalLen(), idata.getFNumber(), idata.getDateTimeAsTS());
  345             iter = ffList.emplace(key, n);
  346         } else {
  347             while(iter != ffList.end() && iter->second.key() == key && ABS(iter->second.timestamp - ri.get_timestamp()) > 60 * 60 * 6) { // 6 hour difference
  348                 ++iter;
  349             }
  350 
  351             if(iter != ffList.end()) {
  352                 iter->second.pathNames.push_back(filename);
  353             } else {
  354                 ffInfo n(filename, idata.getMake(), idata.getModel(), idata.getLens(), idata.getFocalLen(), idata.getFNumber(), idata.getDateTimeAsTS());
  355                 iter = ffList.emplace(key, n);
  356             }
  357         }
  358 
  359         return &(iter->second);
  360 
  361     } catch (Gio::Error&) {}
  362 
  363     return nullptr;
  364 }
  365 
  366 void FFManager::getStat( int &totFiles, int &totTemplates)
  367 {
  368     totFiles = 0;
  369     totTemplates = 0;
  370 
  371     for( ffList_t::iterator iter = ffList.begin(); iter != ffList.end(); ++iter ) {
  372         ffInfo &i = iter->second;
  373 
  374         if( i.pathname.empty() ) {
  375             totTemplates++;
  376             totFiles += i.pathNames.size();
  377         } else {
  378             totFiles++;
  379         }
  380     }
  381 }
  382 
  383 /*  The search for the best match is twofold:
  384  *  if perfect matches for make and model are found, then the list is scanned for lesser distance in time
  385  *  otherwise if no match is found, the whole list is searched for lesser distance in lens and aperture
  386  */
  387 ffInfo* FFManager::find( const std::string &mak, const std::string &mod, const std::string &len, double focal, double apert, time_t t )
  388 {
  389     if( ffList.empty() ) {
  390         return nullptr;
  391     }
  392 
  393     std::string key( ffInfo::key(mak, mod, len, focal, apert) );
  394     ffList_t::iterator iter = ffList.find( key );
  395 
  396     if(  iter != ffList.end() ) {
  397         ffList_t::iterator bestMatch = iter;
  398         time_t bestDeltaTime = ABS(iter->second.timestamp - t);
  399 
  400         for(++iter; iter != ffList.end() && !key.compare( iter->second.key() ); ++iter ) {
  401             time_t d = ABS(iter->second.timestamp - t );
  402 
  403             if( d < bestDeltaTime ) {
  404                 bestMatch = iter;
  405                 bestDeltaTime = d;
  406             }
  407         }
  408 
  409         return &(bestMatch->second);
  410     } else {
  411         iter = ffList.begin();
  412         ffList_t::iterator bestMatch = iter;
  413         double bestD = iter->second.distance(  mak, mod, len, focal, apert );
  414 
  415         for( ++iter; iter != ffList.end(); ++iter ) {
  416             double d = iter->second.distance(  mak, mod, len, focal, apert );
  417 
  418             if( d < bestD ) {
  419                 bestD = d;
  420                 bestMatch = iter;
  421             }
  422         }
  423 
  424         return bestD != INFINITY ? &(bestMatch->second) : nullptr ;
  425     }
  426 }
  427 
  428 RawImage* FFManager::searchFlatField( const std::string &mak, const std::string &mod, const std::string &len, double focal, double apert, time_t t )
  429 {
  430     ffInfo *ff = find( mak, mod, len, focal, apert, t );
  431 
  432     if( ff ) {
  433         return ff->getRawImage();
  434     } else {
  435         return nullptr;
  436     }
  437 }
  438 
  439 RawImage* FFManager::searchFlatField( const Glib::ustring filename )
  440 {
  441     for ( ffList_t::iterator iter = ffList.begin(); iter != ffList.end(); ++iter ) {
  442         if( iter->second.pathname.compare( filename ) == 0  ) {
  443             return iter->second.getRawImage();
  444         }
  445     }
  446 
  447     ffInfo *ff = addFileInfo( filename , false);
  448 
  449     if(ff) {
  450         return ff->getRawImage();
  451     }
  452 
  453     return nullptr;
  454 }
  455 
  456 
  457 // Global variable
  458 FFManager ffm;
  459 
  460 
  461 }
  462