TuttleOFX  1
main.cpp
Go to the documentation of this file.
00001 #include <sam/common/utility.hpp>
00002 #include <sam/common/options.hpp>
00003 
00004 #include <tuttle/host/Graph.hpp>
00005 
00006 #include <boost/filesystem.hpp>
00007 #include <boost/program_options.hpp>
00008 #include <boost/algorithm/string.hpp>
00009 
00010 #include <Sequence.hpp>
00011 
00012 #include <limits>
00013 
00014 using namespace tuttle::host;
00015 namespace bfs = boost::filesystem;
00016 namespace bpo = boost::program_options;
00017 
00018 
00019 static int _notNullImage = 0;
00020 static int _nullFileSize = 0;
00021 static int _corruptedImage = 0;
00022 static int _missingFiles = 0;
00023 static int _processedImages = 0;
00024 
00025 enum EReturnCode {
00026         eReturnCodeOK = 0,
00027         eReturnCodeErrorInImages = 1,
00028         eReturnCodeApplicationError = 2
00029 };
00030 
00031 enum EImageStatus {
00032         eImageStatusDiffNull = 0,
00033         eImageStatusDiffNotNull,
00034         eImageStatusFileSizeError,
00035         eImageStatusNoFile,
00036         eImageStatusImageError
00037 };
00038 
00039 /**
00040  * @brief Process the difference between 2 readers and return status.
00041  */
00042 EImageStatus diffImageStatus(Graph::Node& read1, Graph::Node& read2, Graph::Node& stat, Graph& graph, const bfs::path& filename1, const bfs::path& filename2)
00043 {
00044         if (bfs::exists(filename1) == 0 || bfs::exists(filename2) == 0)
00045                 return eImageStatusNoFile;
00046 
00047         if (bfs::file_size(filename1) == 0 || bfs::file_size(filename2) == 0)
00048                 return eImageStatusFileSizeError;
00049 
00050         try
00051         {
00052                 // Setup parameters
00053                 read1.getParam("filename").setValue(filename1.string());
00054                 read2.getParam("filename").setValue(filename2.string());
00055                 
00056                 graph.compute(stat);
00057 
00058                 std::stringstream stream;
00059                 stream << "diff = ";
00060                 for (unsigned int i = 0; i < 3; ++i)
00061                 {
00062                         stream << stat.getParam("quality").getDoubleValueAtIndex(i) << "  ";
00063                 }
00064                 TUTTLE_LOG_TRACE( stream.str() );
00065 
00066                 for (unsigned int i = 0; i < 3; ++i)
00067                 {
00068                         if (stat.getParam("quality").getDoubleValueAtIndex(i) != 0.0 )
00069                                 return eImageStatusDiffNotNull;
00070                 }
00071                 //TUTTLE_LOG_TRACE( stat );
00072 
00073                 return eImageStatusDiffNull;
00074         }
00075         catch (...)
00076         {
00077                 TUTTLE_LOG_ERROR( boost::current_exception() );
00078                 TUTTLE_LOG_ERROR( boost::current_exception_diagnostic_information() );
00079                 return eImageStatusImageError;
00080         }
00081 }
00082 
00083 /**
00084  * @brief Process difference between a reader and a generator.
00085  */
00086 EImageStatus diffImageStatus(Graph::Node& read1, Graph::Node& read2, Graph::Node& stat, Graph& graph, const bfs::path& filename, const std::vector<std::string>& generatorOptions )
00087 {
00088         if ( ! bfs::exists(filename))
00089                 return eImageStatusNoFile;
00090 
00091         if ( bfs::file_size(filename) == 0 )
00092                 return eImageStatusFileSizeError;
00093 
00094         try
00095         {
00096                 // Setup parameters
00097                 read1.getParam("filename").setValue(filename.string());
00098                 for( size_t i=0; i<generatorOptions.size(); i++ )
00099                 {
00100                         std::vector<std::string> opt;
00101                         boost::split(opt, generatorOptions.at(i), boost::is_any_of("="));
00102                         int optvalue = atoi ( opt.at(1).c_str() );
00103                         if( optvalue == 0 )
00104                         {
00105                                 std::vector<std::string> optList;
00106                                 boost::split(optList, opt.at(1), boost::is_any_of(","));
00107                                 switch( optList.size() )
00108                                 {
00109                                         case 1 :
00110                                         { // not a number, set a string parameter
00111                                                 read2.getParam(opt.at(0)).setValue( opt.at(1) );
00112                                                 break;
00113                                         }
00114                                         case 2 :
00115                                         {
00116                                                 float opt0 = atof ( optList.at(0).c_str() );
00117                                                 float opt1 = atof ( optList.at(1).c_str() );
00118                                                 read2.getParam(opt.at(0)).setValue( opt0, opt1 );
00119                                                 break;
00120                                         }
00121                                         case 3 :
00122                                         {
00123                                                 float opt0 = atof ( optList.at(0).c_str() );
00124                                                 float opt1 = atof ( optList.at(1).c_str() );
00125                                                 float opt2 = atof ( optList.at(2).c_str() );
00126                                                 read2.getParam(opt.at(0)).setValue( opt0, opt1, opt2 );
00127                                                 break;
00128                                         }/*
00129                                         case 4 :
00130                                         {
00131                                                 double opt0 = atof ( optList.at(0).c_str() );
00132                                                 double opt1 = atof ( optList.at(1).c_str() );
00133                                                 double opt2 = atof ( optList.at(2).c_str() );
00134                                                 //double opt3 = atof ( optList.at(3).c_str() );
00135                                                 read2.getParam(opt.at(0)).setValue( opt0, opt1, opt2 );
00136                                         }*/
00137                                         default :
00138                                         {
00139                                                 for(size_t i=0; i<opt.size(); i++)
00140                                                                 TUTTLE_LOG_VAR( TUTTLE_INFO, opt.at(i));
00141                                                 TUTTLE_LOG_ERROR( "unable to process " << optList.size() << " arguments" );
00142                                                 break;
00143                                         }
00144                                 }
00145 
00146                                 
00147                         }
00148                         else
00149                         {
00150                                 read2.getParam(opt.at(0)).setValue( optvalue );
00151                         }
00152                 }
00153 
00154                 graph.compute(stat);
00155 
00156                 std::stringstream stream;
00157                 stream << "diff = ";
00158                 for (unsigned int i = 0; i < 3; ++i)
00159                 {
00160                         stream << stat.getParam("quality").getDoubleValueAtIndex(i) << "  ";
00161                 }
00162                 TUTTLE_LOG_TRACE( stream.str() );
00163 
00164                 for (unsigned int i = 0; i < 3; ++i)
00165                 {
00166                         if (stat.getParam("quality").getDoubleValueAtIndex(i) != 0.0 )
00167                                 return eImageStatusDiffNotNull;
00168                 }
00169                 //TUTTLE_LOG_TRACE( stat );
00170 
00171                 return eImageStatusDiffNull;
00172         }
00173         catch (...)
00174         {
00175                 TUTTLE_LOG_ERROR( boost::current_exception() );
00176                 TUTTLE_LOG_ERROR( boost::current_exception_diagnostic_information() );
00177                 return eImageStatusImageError;
00178         }
00179 }
00180 
00181 /**
00182  * @brief Difference between 2 reader's node associated at 2 files
00183  */
00184 EImageStatus diffFile(Graph::Node& read1, Graph::Node& read2, Graph::Node& stat, Graph& graph, const bfs::path& filename1, const bfs::path& filename2)
00185 {
00186         EImageStatus s = diffImageStatus(read1, read2, stat, graph, filename1, filename2);
00187 
00188         std::string message;
00189         switch (s) {
00190                 case eImageStatusDiffNull:
00191                         break;
00192                 case eImageStatusDiffNotNull:
00193                         message = "Diff not null: ";
00194                         ++_notNullImage;
00195                         break;
00196                 case eImageStatusFileSizeError:
00197                         message = "Null file size: ";
00198                         ++_nullFileSize;
00199                         break;
00200                 case eImageStatusNoFile:
00201                         message = "Missing file: ";
00202                         ++_missingFiles;
00203                         break;
00204                 case eImageStatusImageError:
00205                         message = "Corrupted image: ";
00206                         ++_corruptedImage;
00207                         break;
00208         }
00209         ++_processedImages;
00210         TUTTLE_LOG_WARNING( message << filename1 << "  and: " << filename2 );
00211         return s;
00212 }
00213 
00214 /**
00215  * @brief Difference between 1 reader and 1 generator associated with 1 file and vector of options for the generator
00216  */
00217 EImageStatus diffFile(Graph::Node& read1, Graph::Node& read2, Graph::Node& stat, Graph& graph, const bfs::path& filename1, const std::vector<std::string>& generatorOptions)
00218 {
00219         EImageStatus s = diffImageStatus(read1, read2, stat, graph, filename1, generatorOptions);
00220 
00221         std::string message;
00222         switch (s) {
00223                 case eImageStatusDiffNull:
00224                         break;
00225                 case eImageStatusDiffNotNull:
00226                         message = "Diff not null: ";
00227                         ++_notNullImage;
00228                         break;
00229                 case eImageStatusFileSizeError:
00230                         message = "Null file size: ";
00231                         ++_nullFileSize;
00232                         break;
00233                 case eImageStatusNoFile:
00234                         message = "Missing file: ";
00235                         ++_missingFiles;
00236                         break;
00237                 case eImageStatusImageError:
00238                         message = "Corrupted image: ";
00239                         ++_corruptedImage;
00240                         break;
00241         }
00242         ++_processedImages;
00243         TUTTLE_LOG_WARNING( message << filename1 << "  and  the generator" );
00244         return s;
00245 }
00246 
00247 void diffSequence(Graph::Node& read1, Graph::Node& read2, Graph::Node& stat, Graph& graph, const sequenceParser::Sequence& seq1, const sequenceParser::Sequence& seq2)
00248 {
00249         for (sequenceParser::Time t = seq1.getFirstTime(); t <= seq1.getLastTime(); ++t)
00250         {
00251                 diffFile(read1, read2, stat, graph, seq1.getAbsoluteFilenameAt(t), seq2.getAbsoluteFilenameAt(t));
00252         }
00253 }
00254 
00255 void diffSequence(Graph::Node& read1, Graph::Node& read2, Graph::Node& stat, Graph& graph, const sequenceParser::Sequence& seq1, const sequenceParser::Sequence& seq2, const sequenceParser::Time first,
00256                                   const sequenceParser::Time last)
00257 {
00258         for (sequenceParser::Time t = first; t <= last; ++t)
00259         {
00260                 diffFile(read1, read2, stat, graph, seq1.getAbsoluteFilenameAt(t), seq2.getAbsoluteFilenameAt(t));
00261         }
00262 }
00263 
00264 void displayHelp(bpo::options_description &desc)
00265 {
00266         using namespace sam;
00267         boost::shared_ptr<tuttle::common::Color>  color( tuttle::common::Color::get() );
00268         
00269         TUTTLE_LOG_INFO( color->_blue << "TuttleOFX project [" << kUrlTuttleofxProject << "]" << color->_std );
00270         TUTTLE_LOG_INFO( "" );
00271         TUTTLE_LOG_INFO( color->_blue << "NAME" << color->_std);
00272         TUTTLE_LOG_INFO( color->_green << "\tsam-diff - compute difference between 2 images/sequences" << color->_std );
00273         TUTTLE_LOG_INFO( "" );
00274         TUTTLE_LOG_INFO( color->_blue << "SYNOPSIS" << color->_std);
00275         TUTTLE_LOG_INFO( color->_green << "\tsam-diff [reader] [input] [reader] [input] [options]" << color->_std );
00276         TUTTLE_LOG_INFO( "" );
00277         TUTTLE_LOG_INFO( color->_blue << "DESCRIPTION" << color->_std);
00278         TUTTLE_LOG_INFO( color->_green << "\tDiff if sequence have black images." << color->_std );
00279         TUTTLE_LOG_INFO( color->_green << "\tThis tools process the PSNR of an image, and if it's null, the image is considered black." << color->_std );
00280         TUTTLE_LOG_INFO( color->_green << "\tOnly compare RGB layout, not Alpha." << color->_std );
00281         TUTTLE_LOG_INFO( "" );
00282         TUTTLE_LOG_INFO( color->_blue << "OPTIONS" << color->_std );
00283         TUTTLE_LOG_INFO( "" );
00284         TUTTLE_LOG_INFO( desc);
00285 
00286         TUTTLE_LOG_INFO( color->_blue << "EXAMPLES" << color->_std << std::left );
00287         SAM_EXAMPLE_TITLE_COUT( "Sequence possible definitions: ");
00288         SAM_EXAMPLE_LINE_COUT ( "Auto-detect padding : ", "seq.@.jpg");
00289         SAM_EXAMPLE_LINE_COUT ( "Padding of 8 (usual style): ", "seq.########.jpg");
00290         SAM_EXAMPLE_TITLE_COUT( "Compare two images: ");
00291         SAM_EXAMPLE_LINE_COUT ( "", "sam-diff --reader tuttle.jpegreader --input path/image.jpg --reader tuttle.jpegreader --input anotherPath/image.jpg");
00292         SAM_EXAMPLE_TITLE_COUT( "Compare two sequences: ");
00293         SAM_EXAMPLE_LINE_COUT ( "", "sam-diff --reader tuttle.jpegreader --input path/seq.@.jpg --reader tuttle.jpegreader --input anotherPath/seq.@.jpg --range 677836 677839");
00294         SAM_EXAMPLE_TITLE_COUT( "Compare one sequence with one generator (generator need to be every time the second node): ");
00295         SAM_EXAMPLE_LINE_COUT ( "", "sam-diff --reader tuttle.jpegreader --input path/seq.@.jpg --reader tuttle.constant --generator-args width=500 components=rgb --range 677836 677839" );
00296         TUTTLE_LOG_INFO( "" );
00297 }
00298 
00299 int main( int argc, char** argv )
00300 {
00301         signal(SIGINT, signal_callback_handler);
00302 
00303         using namespace tuttle::common;
00304         using namespace sam;
00305         
00306         boost::shared_ptr<formatters::Formatter> formatter( formatters::Formatter::get() );
00307         boost::shared_ptr<Color>                 color( Color::get() );
00308 
00309     try {
00310         std::vector<std::string> inputs;
00311         std::vector<std::string> nodeId;
00312         bool hasRange = false;
00313                 bool script   = false;
00314         std::vector<int> range;
00315                 
00316                 std::vector<std::string> generator;
00317 
00318         bpo::options_description desc;
00319         bpo::options_description hidden;
00320 
00321                 formatter->init_logging();
00322                 
00323                 desc.add_options()
00324                                 ( kHelpOptionString,   kHelpOptionMessage )
00325                                 ( kReaderOptionString, bpo::value(&nodeId), kReaderOptionMessage )
00326                                 ( kInputOptionString,  bpo::value(&inputs), kInputOptionMessage )
00327                                 ( kRangeOptionString,  bpo::value(&range)->multitoken(), kRangeOptionMessage )
00328                                 ( kGeneratorArgsOptionString, bpo::value(&generator)->multitoken(),  kGeneratorArgsOptionMessage )
00329                                 ( kVerboseOptionString,       bpo::value<int>()->default_value( 2 ), kVerboseOptionMessage )
00330                                 ( kQuietOptionString,  kQuietOptionMessage )
00331                                 ( kBriefOptionString,  kBriefOptionMessage )
00332                                 ( kColorOptionString,  kColorOptionMessage )
00333                                 ( kScriptOptionString, kScriptOptionMessage );
00334 
00335         // describe hidden options
00336         hidden.add_options()
00337                                 ( kEnableColorOptionString, bpo::value<std::string>(), kEnableColorOptionMessage );
00338 
00339         bpo::options_description cmdline_options;
00340         cmdline_options.add(desc).add(hidden);
00341 
00342         bpo::positional_options_description pod;
00343         pod.add(kInputOptionLongName, -1);
00344 
00345         bpo::variables_map vm;
00346 
00347         try {
00348             //parse the command line, and put the result in vm
00349             bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(pod).run(), vm);
00350 
00351             // get environment options and parse them
00352             if (const char* env_diff_options = std::getenv("SAM_DIFF_OPTIONS")) {
00353                 const std::vector<std::string> vecOptions = bpo::split_unix(env_diff_options, " ");
00354                 bpo::store(bpo::command_line_parser(vecOptions).options(cmdline_options).positional(pod).run(), vm);
00355             }
00356             if (const char* env_diff_options = std::getenv("SAM_OPTIONS")) {
00357                 const std::vector<std::string> vecOptions = bpo::split_unix(env_diff_options, " ");
00358                 bpo::store(bpo::command_line_parser(vecOptions).options(cmdline_options).positional(pod).run(), vm);
00359             }
00360             bpo::notify(vm);
00361         } catch (const bpo::error& e) {
00362             TUTTLE_LOG_ERROR( "sam-diff: command line error: " << e.what() );
00363             exit(254);
00364         } catch (...) {
00365             TUTTLE_LOG_ERROR( "sam-diff: unknown error in command line." );
00366             exit(254);
00367         }
00368 
00369                 if (vm.count(kScriptOptionLongName)) {
00370                         // disable color, disable directory printing and set relative path by default
00371                         script = true;
00372                 }
00373                 
00374                 switch( vm[ kVerboseOptionLongName ].as< int >() )
00375                 {
00376                         case 0 :  formatter->setLogLevel( boost::log::trivial::trace   ); break;
00377                         case 1 :  formatter->setLogLevel( boost::log::trivial::debug   ); break;
00378                         case 2 :  formatter->setLogLevel( boost::log::trivial::info    ); break;
00379                         case 3 :  formatter->setLogLevel( boost::log::trivial::warning ); break;
00380                         case 4 :  formatter->setLogLevel( boost::log::trivial::error   ); break;
00381                         case 5 :  formatter->setLogLevel( boost::log::trivial::fatal   ); break;
00382                         default : formatter->setLogLevel( boost::log::trivial::warning ); break;
00383                 }
00384                 if( vm.count(kQuietOptionLongName) )
00385                 {
00386                         formatter->setLogLevel( boost::log::trivial::fatal );
00387                 }
00388 
00389                 if( vm.count( kColorOptionLongName ) && !script )
00390                 {
00391                         color->enable();
00392                 }
00393                 
00394                 if( vm.count( kEnableColorOptionLongName ) && !script )
00395                 {
00396                         const std::string str = vm[kEnableColorOptionLongName].as<std::string>();
00397                         if( string_to_boolean(str) )
00398                         {
00399                                 color->enable();
00400                         }
00401                         else
00402                         {
00403                                 color->disable();
00404                         }
00405                 }
00406 
00407         if( vm.count( kBriefOptionLongName ) )
00408                 {
00409             TUTTLE_LOG_INFO( color->_green << "diff image files" << color->_std );
00410             return 0;
00411         }
00412 
00413         if (vm.count(kHelpOptionLongName)) {
00414             displayHelp(desc);
00415             return 0;
00416         }
00417         if (!vm.count(kReaderOptionLongName)) {
00418             TUTTLE_LOG_ERROR( "sam-diff : no reader specified." );
00419             displayHelp(desc);
00420             return 254;
00421         }
00422         if (!vm.count(kInputOptionLongName)) {
00423             TUTTLE_LOG_ERROR( "sam-diff : no input specified." );
00424             displayHelp(desc);
00425             return 254;
00426         }
00427                 
00428                 if (vm.count(kGeneratorArgsOptionLongName)) {
00429                         generator = vm[kGeneratorArgsOptionLongName].as<std::vector<std::string> >();
00430                 }
00431                 
00432                 nodeId    = vm[kReaderOptionLongName].as<std::vector<std::string> >();
00433                 inputs    = vm[kInputOptionLongName].as<std::vector<std::string> >();
00434                 
00435                 if( nodeId.size() != 2 )
00436                 {
00437                         TUTTLE_LOG_ERROR( "sam-diff : require 2 input nodes." );
00438                         displayHelp(desc);
00439                         return 254;
00440                 }
00441                 if (vm.count(kRangeOptionLongName))
00442                 {
00443                         range = vm[kRangeOptionLongName].as<std::vector<int> >();
00444                         hasRange = (range.size() == 2);
00445                 }
00446 
00447                 core().preload();
00448                 Graph graph;
00449                 
00450                 TUTTLE_LOG_TRACE( "in1: " << nodeId.at(0) );
00451                 TUTTLE_LOG_TRACE( "in2: " << nodeId.at(1) );
00452                 
00453                 Graph::Node& read1 = graph.createNode(nodeId.at(0));
00454                 Graph::Node& read2 = graph.createNode(nodeId.at(1));
00455                 //Graph::Node& viewer = graph.createNode( "tuttle.viewer" );
00456                 Graph::Node& stat = graph.createNode("tuttle.diff");
00457                 //graph.connect( viewer, stat );
00458                 graph.connect(read1, stat);
00459                 graph.connect(read2, stat.getAttribute("SourceB"));
00460 
00461                 switch( inputs.size() )
00462                 {
00463                         case 0 :
00464                         {
00465                                 break;
00466                         }
00467                         case 1 :
00468                         {
00469                                 bfs::path path1 = inputs.at(0);
00470         
00471                                 if ( bfs::exists(path1)) {
00472                                         // process a file
00473                                         diffFile(read1, read2, stat, graph, path1, generator );
00474                                 }
00475                                 else
00476                                 {
00477                                         // process a sequence
00478                                         /*
00479                                         try {
00480                                                 Sequence s1(path1);
00481                                                 if (hasRange) {
00482                                                         diffSequence(read1, read2, stat, graph, s1, generator, range[0], range[1]);
00483                                                 } else {
00484                                                         diffSequence(read1, read2, stat, graph, s1, generator);
00485                                                 }
00486                                         } catch (...) {
00487                                                 std::cerr << "Unrecognized pattern " << path1 << std::endl;
00488                                                 return eReturnCodeApplicationError;
00489                                         }*/
00490                                 }
00491                                 break;
00492                         }
00493                         case 2 :
00494                         {
00495                                 bfs::path path1 = inputs.at(0);
00496                                 bfs::path path2 = inputs.at(1);
00497 
00498 
00499                                 if (bfs::exists(path1))
00500                                 {
00501                                         if (!bfs::exists(path2))
00502                                         {
00503                                                 TUTTLE_LOG_ERROR( "could not find file or directory 2 (first is not a sequence)." );
00504                                                 return 0;
00505                                         }
00506                                         /*
00507                                          if( bfs::is_directory( path1 ) )
00508                                          {
00509                                          std::list<boost::shared_ptr<FileObject> > fObjects;
00510                                          fObjects = fileObjectsInDir( path );
00511                                          BOOST_FOREACH( const boost::shared_ptr<FileObject> fObj, fObjects )
00512                                          {
00513                                          switch( fObj->getMaskType() )
00514                                          {
00515                                          case eMaskTypeSequence:
00516                                          {
00517                                          diffSequence( read1, read2, stat, graph, dynamic_cast<const Sequence&>( *fObj ) );
00518                                          break;
00519                                          }
00520                                          case eMaskTypeFile:
00521                                          {
00522                                          const File fFile = dynamic_cast<const File&>( *fObj );
00523                                          diffFile( read1, read2, stat, graph, fFile.getAbsoluteFilename(), fFile.getAbsoluteFilename() );
00524                                          break;
00525                                          }
00526                                          case eMaskTypeDirectory:
00527                                          case eMaskTypeUndefined:
00528                                          break;
00529                                          }
00530                                          }
00531                                          }
00532                                          else
00533                                          {*/
00534                                                 diffFile(read1, read2, stat, graph, path1, path2);
00535                                          //}
00536                                 }
00537                                 else
00538                                 {
00539                                         try
00540                                         {
00541                                                 sequenceParser::Sequence s1(path1);
00542                                                 sequenceParser::Sequence s2(path2);
00543                                                 if (hasRange)
00544                                                 {
00545                                                         diffSequence(read1, read2, stat, graph, s1, s2, range[0], range[1]);
00546                                                 }
00547                                                 else
00548                                                 {
00549                                                         diffSequence(read1, read2, stat, graph, s1, s2);
00550                                                 }
00551                                         }
00552                                         catch(...)
00553                                         {
00554                                                 TUTTLE_LOG_WARNING( "Unrecognized pattern " << path1 << " or " << path2 );
00555                                                 return eReturnCodeApplicationError;
00556                                         }
00557                                 }
00558                         }
00559                 }
00560         }
00561         catch (...)
00562         {
00563                 TUTTLE_LOG_ERROR( "sam-diff error " << boost::current_exception_diagnostic_information() );
00564                 return 255;
00565         }
00566         
00567         TUTTLE_LOG_INFO( "________________________________________");
00568         TUTTLE_LOG_INFO( "Processed images: " << _processedImages);
00569         TUTTLE_LOG_INFO( "Different images: " << _notNullImage);
00570         TUTTLE_LOG_INFO( "Null file size: " << _nullFileSize);
00571         TUTTLE_LOG_INFO( "Corrupted images: " << _corruptedImage);
00572         TUTTLE_LOG_INFO( "Holes in sequence: " << _missingFiles);
00573         TUTTLE_LOG_INFO( "________________________________________");
00574 
00575         return _notNullImage + _nullFileSize + _corruptedImage + _missingFiles;
00576 }
00577