添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

" Fossies " - the Fresh Open Source Software Archive

Member "opencv-4.10.0/modules/imgcodecs/src/loadsave.cpp" (2 Jun 2024, 42509 Bytes) of package / linux / misc / opencv-4.10.0.tar.gz :

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 "loadsave.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.9.0_vs_4.10.0 .
    1 /*M///////////////////////////////////////////////////////////////////////////////////////
    3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
    5 //  By downloading, copying, installing or using the software you agree to this license.
    6 //  If you do not agree to this license, do not download, install,
    7 //  copy or use the software.
   10 //                        Intel License Agreement
   11 //                For Open Source Computer Vision Library
   12 //
   14 // Third party copyrights are property of their respective owners.
   15 //
   16 // Redistribution and use in source and binary forms, with or without modification,
   17 // are permitted provided that the following conditions are met:
   18 //
   19 //   * Redistribution's of source code must retain the above copyright notice,
   20 //     this list of conditions and the following disclaimer.
   21 //
   22 //   * Redistribution's in binary form must reproduce the above copyright notice,
   23 //     this list of conditions and the following disclaimer in the documentation
   24 //     and/or other materials provided with the distribution.
   25 //
   26 //   * The name of Intel Corporation may not be used to endorse or promote products
   27 //     derived from this software without specific prior written permission.
   28 //
   29 // This software is provided by the copyright holders and contributors "as is" and
   30 // any express or implied warranties, including, but not limited to, the implied
   31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
   32 // In no event shall the Intel Corporation or contributors be liable for any direct,
   33 // indirect, incidental, special, exemplary, or consequential damages
   34 // (including, but not limited to, procurement of substitute goods or services;
   35 // loss of use, data, or profits; or business interruption) however caused
   36 // and on any theory of liability, whether in contract, strict liability,
   37 // or tort (including negligence or otherwise) arising in any way out of
   38 // the use of this software, even if advised of the possibility of such damage.
   39 //
   40 //M*/
   42 //
   43 //  Loading and saving images.
   44 //
   46 #include "precomp.hpp"
   47 #include "grfmts.hpp"
   48 #include "utils.hpp"
   49 #include "exif.hpp"
   50 #undef min
   51 #undef max
   52 #include <iostream>
   53 #include <fstream>
   54 #include <cerrno>
   55 #include <opencv2/core/utils/logger.hpp>
   56 #include <opencv2/core/utils/configuration.private.hpp>
   57 #include <opencv2/imgcodecs.hpp>
   61 /****************************************************************************************\
   62 *                                      Image Codecs                                      *
   63 \****************************************************************************************/
   65 namespace cv  {
   67 static const size_t CV_IO_MAX_IMAGE_PARAMS = cv::utils::getConfigurationParameterSizeT("OPENCV_IO_MAX_IMAGE_PARAMS", 50);
   68 static const size_t CV_IO_MAX_IMAGE_WIDTH = utils::getConfigurationParameterSizeT("OPENCV_IO_MAX_IMAGE_WIDTH", 1 << 20);
   69 static const size_t CV_IO_MAX_IMAGE_HEIGHT = utils::getConfigurationParameterSizeT("OPENCV_IO_MAX_IMAGE_HEIGHT", 1 << 20);
   70 static const size_t CV_IO_MAX_IMAGE_PIXELS = utils::getConfigurationParameterSizeT("OPENCV_IO_MAX_IMAGE_PIXELS", 1 << 30);
   72 static Size validateInputImageSize(const Size& size)
   74     CV_Assert(size.width > 0);
   75     CV_Assert(static_cast<size_t>(size.width) <= CV_IO_MAX_IMAGE_WIDTH);
   76     CV_Assert(size.height > 0);
   77     CV_Assert(static_cast<size_t>(size.height) <= CV_IO_MAX_IMAGE_HEIGHT);
   78     uint64 pixels = (uint64)size.width * (uint64)size.height;
   79     CV_Assert(pixels <= CV_IO_MAX_IMAGE_PIXELS);
   80     return size;
   84 namespace  {
   86 class ByteStreamBuffer: public std::streambuf
   88 public:
   89     ByteStreamBuffer(char* base, size_t length)
   90      {
   91         setg(base, base, base + length);
   92      }
   94 protected:
   95     virtual pos_type seekoff( off_type offset,
   96                               std::ios_base::seekdir dir,
   97                               std::ios_base::openmode ) CV_OVERRIDE
   98      {
   99         char* whence = eback();
  100         if (dir == std::ios_base::cur)
  101 




    
         {
  102             whence = gptr();
  103          }
  104         else if (dir == std::ios_base::end)
  105          {
  106             whence = egptr();
  107          }
  108         char* to = whence + offset;
  110         // check limits
  111         if (to >= eback() && to <= egptr())
  112          {
  113             setg(eback(), to, egptr());
  114             return gptr() - eback();
  115          }
  117         return -1;
  118      }
  119  };
  121  }
  123 /**
  124  * @struct ImageCodecInitializer
  125  *
  126  * Container which stores the registered codecs to be used by OpenCV
  127 */
  128 struct ImageCodecInitializer
  129  {
  130     /**
  131      * Default Constructor for the ImageCodeInitializer
  132     */
  133     ImageCodecInitializer()
  134      {
  135 #ifdef HAVE_AVIF
  136         decoders.push_back(makePtr<AvifDecoder>());
  137         encoders.push_back(makePtr<AvifEncoder>());
  138 #endif
  139         /// BMP Support
  140         decoders.push_back( makePtr<BmpDecoder>() );
  141         encoders.push_back( makePtr<BmpEncoder>() );
  143     #ifdef HAVE_IMGCODEC_HDR
  144         decoders.push_back( makePtr<HdrDecoder>() );
  145         encoders.push_back( makePtr<HdrEncoder>() );
  146     #endif
  147     #ifdef HAVE_JPEG
  148         decoders.push_back( makePtr<JpegDecoder>() );
  149         encoders.push_back( makePtr<JpegEncoder>() );
  150     #endif
  151     #ifdef HAVE_WEBP
  152         decoders.push_back( makePtr<WebPDecoder>() );
  153         encoders.push_back( makePtr<WebPEncoder>() );
  154     #endif
  155     #ifdef HAVE_IMGCODEC_SUNRASTER
  156         decoders.push_back( makePtr<SunRasterDecoder>() );
  157         encoders.push_back( makePtr<SunRasterEncoder>() );
  158     #endif
  159     #ifdef HAVE_IMGCODEC_PXM
  160         decoders.push_back( makePtr<PxMDecoder>() );
  161         encoders.push_back( makePtr<PxMEncoder>(PXM_TYPE_AUTO) );
  162         encoders.push_back( makePtr<PxMEncoder>(PXM_TYPE_PBM) );
  163         encoders.push_back( makePtr<PxMEncoder>(PXM_TYPE_PGM) );
  164         encoders.push_back( makePtr<PxMEncoder>(PXM_TYPE_PPM) );
  165         decoders.push_back( makePtr<PAMDecoder>() );
  166         encoders.push_back( makePtr<PAMEncoder>() );
  167     #endif
  168     #ifdef HAVE_IMGCODEC_PFM
  169         decoders.push_back( makePtr<PFMDecoder>() );
  170         encoders.push_back( makePtr<PFMEncoder>() );
  171     #endif
  172     #ifdef HAVE_TIFF
  173         decoders.push_back( makePtr<TiffDecoder>() );
  174         encoders.push_back( makePtr<TiffEncoder>() );
  175     #endif
  176     #ifdef HAVE_SPNG
  177         decoders.push_back( makePtr<SPngDecoder>() );
  178         encoders.push_back( makePtr<SPngEncoder>() );
  179     #elif defined(HAVE_PNG)
  180         decoders.push_back( makePtr<PngDecoder>() );
  181         encoders.push_back( makePtr<PngEncoder>() );
  182     #endif
  183     #ifdef HAVE_GDCM
  184         decoders.push_back( makePtr<DICOMDecoder>() );
  185     #endif
  186     #ifdef HAVE_JASPER
  187         decoders.push_back( makePtr<Jpeg2KDecoder>() );
  188         encoders.push_back( makePtr<Jpeg2KEncoder>() );
  189     #endif
  190     #ifdef HAVE_OPENJPEG
  191         decoders.push_back( makePtr<Jpeg2KJP2OpjDecoder>() );
  192         decoders.push_back( makePtr<Jpeg2KJ2KOpjDecoder>() );
  193         encoders.push_back( makePtr<Jpeg2KOpjEncoder>() );
  194     #endif
  195     #ifdef HAVE_OPENEXR
  196         decoders.push_back( makePtr<ExrDecoder>() );
  197         encoders.push_back( makePtr<ExrEncoder>() );
  198     #endif
  200     #ifdef HAVE_GDAL
  201         /// Attach the GDAL Decoder
  202         decoders.push_back( makePtr<GdalDecoder>() );
  203     #endif/*HAVE_GDAL*/
  204      }
  206     std::vector<ImageDecoder> decoders;
  207     std




    
::vector<ImageEncoder> encoders;
  208  };
  210 static
  211 ImageCodecInitializer& getCodecs()
  212  {
  213     static ImageCodecInitializer g_codecs;
  214     return g_codecs;
  215  }
  217 /**
  218  * Find the decoders
  219  *
  220  * @param[in] filename File to search
  221  *
  222  * @return Image decoder to parse image file.
  223 */
  224 static ImageDecoder findDecoder( const String& filename )  {
  226     size_t i, maxlen = 0;
  228     /// iterate through list of registered codecs
  229     ImageCodecInitializer& codecs = getCodecs();
  230     for( i = 0; i < codecs.decoders.size(); i++ )
  231      {
  232         size_t len = codecs.decoders[i]->signatureLength();
  233         maxlen = std::max(maxlen, len);
  234      }
  236     /// Open the file
  237     FILE* f= fopen( filename.c_str(), "rb" );
  239     /// in the event of a failure, return an empty image decoder
  240     if( !f )  {
  241         CV_LOG_WARNING(NULL, "imread_('" << filename << "'): can't open/read file: check file path/integrity");
  242         return ImageDecoder();
  243      }
  245     // read the file signature
  246     String signature(maxlen, ' ');
  247     maxlen = fread( (void*)signature.c_str(), 1, maxlen, f );
  248     fclose(f);
  249     signature = signature.substr(0, maxlen);
  251     /// compare signature against all decoders
  252     for( i = 0; i < codecs.decoders.size(); i++ )
  253      {
  254         if( codecs.decoders[i]->checkSignature(signature) )
  255             return codecs.decoders[i]->newDecoder();
  256      }
  258     /// If no decoder was found, return base type
  259     return ImageDecoder();
  260  }
  262 static ImageDecoder findDecoder( const Mat& buf )
  263  {
  264     size_t i, maxlen = 0;
  266     if( buf.rows*buf.cols < 1 || !buf.isContinuous() )
  267         return ImageDecoder();
  269     ImageCodecInitializer& codecs = getCodecs();
  270     for( i = 0; i < codecs.decoders.size(); i++ )
  271      {
  272         size_t len = codecs.decoders[i]->signatureLength();
  273         maxlen = std::max(maxlen, len);
  274      }
  276     String signature(maxlen, ' ');
  277     size_t bufSize = buf.rows*buf.cols*buf.elemSize();
  278     maxlen = std::min(maxlen, bufSize);
  279     memcpy( (void*)signature.c_str(), buf.data, maxlen );
  281     for( i = 0; i < codecs.decoders.size(); i++ )
  282      {
  283         if( codecs.decoders[i]->checkSignature(signature) )
  284             return codecs.decoders[i]->newDecoder();
  285      }
  287     return ImageDecoder();
  288  }
  290 static ImageEncoder findEncoder( const String& _ext )
  291  {
  292     if( _ext.size() <= 1 )
  293         return ImageEncoder();
  295     const char* ext = strrchr( _ext.c_str(), '.' );
  296     if( !ext )
  297         return ImageEncoder();
  298     int len = 0;
  299     for( ext++; len < 128 && isalnum(ext[len]); len++ )
  300         ;
  302     ImageCodecInitializer& codecs = getCodecs();
  303     for( size_t i = 0; i < codecs.encoders.size(); i++ )
  304      {
  305         String description = codecs.encoders[i]->getDescription();
  306         const char* descr = strchr( description.c_str(), '(' );
  308         while( descr )
  309 




    
         {
  310             descr = strchr( descr + 1, '.' );
  311             if( !descr )
  312                 break;
  313             int j = 0;
  314             for( descr++; j < len && isalnum(descr[j]) ; j++ )
  315              {
  316                 int c1 = tolower(ext[j]);
  317                 int c2 = tolower(descr[j]);
  318                 if( c1 != c2 )
  319                     break;
  320              }
  321             if( j == len && !isalnum(descr[j]))
  322                 return codecs.encoders[i]->newEncoder();
  323             descr += j;
  324          }
  325      }
  327     return ImageEncoder();
  328  }
  331 static void ExifTransform(int orientation, Mat& img)
  332  {
  333     switch( orientation )
  334      {
  335         case    IMAGE_ORIENTATION_TL: //0th row == visual top, 0th column == visual left-hand side
  336             //do nothing, the image already has proper orientation
  337             break;
  338         case    IMAGE_ORIENTATION_TR: //0th row == visual top, 0th column == visual right-hand side
  339             flip(img, img, 1); //flip horizontally
  340             break;
  341         case    IMAGE_ORIENTATION_BR: //0th row == visual bottom, 0th column == visual right-hand side
  342             flip(img, img, -1);//flip both horizontally and vertically
  343             break;
  344         case    IMAGE_ORIENTATION_BL: //0th row == visual bottom, 0th column == visual left-hand side
  345             flip(img, img, 0); //flip vertically
  346             break;
  347         case    IMAGE_ORIENTATION_LT: //0th row == visual left-hand side, 0th column == visual top
  348             transpose(img, img);
  349             break;
  350         case    IMAGE_ORIENTATION_RT: //0th row == visual right-hand side, 0th column == visual top
  351             transpose(img, img);
  352             flip(img, img, 1); //flip horizontally
  353             break;
  354         case    IMAGE_ORIENTATION_RB: //0th row == visual right-hand side, 0th column == visual bottom
  355             transpose(img, img);
  356             flip(img, img, -1); //flip both horizontally and vertically
  357             break;
  358         case    IMAGE_ORIENTATION_LB: //0th row == visual left-hand side, 0th column == visual bottom
  359             transpose(img, img);
  360             flip(img, img, 0); //flip vertically
  361             break;
  362         default:
  363             //by default the image read has normal (JPEG_ORIENTATION_TL) orientation
  364             break;
  365      }
  366  }
  368 static void ApplyExifOrientation(ExifEntry_t orientationTag, Mat& img)
  369  {
  370     int orientation = IMAGE_ORIENTATION_TL;
  372     if (orientationTag.tag != INVALID_TAG)
  373      {
  374         orientation = orientationTag.field_u16; //orientation is unsigned short, so check field_u16
  375         ExifTransform(orientation, img);
  376      }
  377  }
  379 /**
  380  * Read an image into memory and return the information
  381  *
  382  * @param[in] filename File to load
  383  * @param[in] flags Flags
  384  * @param[in] mat Reference to C++ Mat object (If LOAD_MAT)
  385  *
  386 */
  387 static bool
  388 imread_( const String& filename, int flags, Mat& mat )
  389  {
  390     /// Search for the relevant decoder to handle the imagery
  391     ImageDecoder decoder;
  393 #ifdef HAVE_GDAL
  394     if(flags != IMREAD_UNCHANGED && (flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL ) {
  395         decoder = GdalDecoder().newDecoder();
  396      }else {
  397 #endif
  398         decoder = findDecoder( filename );
  399 #ifdef HAVE_GDAL
  400      }
  401 #endif
  403     /// if no decoder was found, return nothing.
  404     if( !decoder ) {
  405         return 0;
  406      }
  408     int scale_denom = 1;
  409     if( flags > IMREAD_LOAD_GDAL )
  410      {
  411         if( flags & IMREAD_REDUCED_GRAYSCALE_2 )
  412             scale_denom = 2;
  413         else if( flags & IMREAD_REDUCED_GRAYSCALE_4 )
  414             scale_denom = 4;
  415         else if( flags &




    
 IMREAD_REDUCED_GRAYSCALE_8 )
  416             scale_denom = 8;
  417      }
  419     /// set the scale_denom in the driver
  420     decoder->setScale( scale_denom );
  422     /// set the filename in the driver
  423     decoder->setSource( filename );
  425     try
  426      {
  427         // read the header to make sure it succeeds
  428         if( !decoder->readHeader() )
  429             return 0;
  430      }
  431     catch (const cv::Exception& e)
  432      {
  433         CV_LOG_ERROR(NULL, "imread_('" << filename << "'): can't read header: " << e.what());
  434         return 0;
  435      }
  436     catch (...)
  437      {
  438         CV_LOG_ERROR(NULL, "imread_('" << filename << "'): can't read header: unknown exception");
  439         return 0;
  440      }
  443     // established the required input image size
  444     Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
  446     // grab the decoded type
  447     int type = decoder->type();
  448     if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED )
  449      {
  450         if( (flags & IMREAD_ANYDEPTH) == 0 )
  451             type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
  453         if( (flags & IMREAD_COLOR) != 0 ||
  454            ((flags & IMREAD_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) )
  455             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
  456         else
  457             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
  458      }
  460     if (mat.empty())
  461      {
  462         mat.create( size.height, size.width, type );
  463      }
  464     else
  465      {
  466         CV_CheckEQ(size, mat.size(), "");
  467         CV_CheckTypeEQ(type, mat.type(), "");
  468         CV_Assert(mat.isContinuous());
  469      }
  471     // read the image data
  472     bool success = false;
  473     try
  474      {
  475         if (decoder->readData(mat))
  476             success = true;
  477      }
  478     catch (const cv::Exception& e)
  479      {
  480         CV_LOG_ERROR(NULL, "imread_('" << filename << "'): can't read data: " << e.what());
  481      }
  482     catch (...)
  483      {
  484         CV_LOG_ERROR(NULL, "imread_('" << filename << "'): can't read data: unknown exception");
  485      }
  486     if (!success)
  487      {
  488         mat.release();
  489         return false;
  490      }
  492     if( decoder->setScale( scale_denom ) > 1 ) // if decoder is JpegDecoder then decoder->setScale always returns 1
  493      {
  494         resize( mat, mat, Size( size.width / scale_denom, size.height / scale_denom ), 0, 0, INTER_LINEAR_EXACT);
  495      }
  497     /// optionally rotate the data if EXIF orientation flag says so
  498     if (!mat.empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
  499      {
  500         ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
  501      }
  503     return true;
  504  }
  507 static bool
  508 imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats, int start, int count)
  509  {
  510     /// Search for the relevant decoder to handle the imagery
  511     ImageDecoder decoder;
  513     CV_CheckGE(start, 0, "Start index cannont be < 0");
  515 #ifdef HAVE_GDAL
  516     if (flags != IMREAD_UNCHANGED && (flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL)  {
  517         decoder = GdalDecoder().newDecoder();
  518      }
  519     else  {
  520 




    
#endif
  521         decoder = findDecoder(filename);
  522 #ifdef HAVE_GDAL
  523      }
  524 #endif
  526     /// if no decoder was found, return nothing.
  527     if (!decoder)  {
  528         return 0;
  529      }
  531     if (count < 0)  {
  532         count = std::numeric_limits<int>::max();
  533      }
  535     /// set the filename in the driver
  536     decoder->setSource(filename);
  538     // read the header to make sure it succeeds
  539     try
  540      {
  541         // read the header to make sure it succeeds
  542         if (!decoder->readHeader())
  543             return 0;
  544      }
  545     catch (const cv::Exception& e)
  546      {
  547         CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read header: " << e.what());
  548         return 0;
  549      }
  550     catch (...)
  551      {
  552         CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read header: unknown exception");
  553         return 0;
  554      }
  556     int current = start;
  558     while (current > 0)
  559      {
  560         if (!decoder->nextPage())
  561          {
  562             return false;
  563          }
  564         --current;
  565      }
  567     while (current < count)
  568      {
  569         // grab the decoded type
  570         int type = decoder->type();
  571         if ((flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED)
  572          {
  573             if ((flags & IMREAD_ANYDEPTH) == 0)
  574                 type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
  576             if ((flags & IMREAD_COLOR) != 0 ||
  577                 ((flags & IMREAD_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1))
  578                 type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
  579             else
  580                 type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
  581          }
  583         // established the required input image size
  584         Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
  586         // read the image data
  587         Mat mat(size.height, size.width, type);
  588         bool success = false;
  589         try
  590          {
  591             if (decoder->readData(mat))
  592                 success = true;
  593          }
  594         catch (const cv::Exception& e)
  595          {
  596             CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read data: " << e.what());
  597          }
  598         catch (...)
  599          {
  600             CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read data: unknown exception");
  601          }
  602         if (!success)
  603             break;
  605         // optionally rotate the data if EXIF' orientation flag says so
  606         if ((flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED)
  607          {
  608             ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
  609          }
  611         mats.push_back(mat);
  612         if (!decoder->nextPage())
  613          {
  614             break;
  615          }
  616         ++current;
  617      }
  619     return !mats.empty();
  620  }
  622 /**
  623  * Read an image
  624  *
  625  *  This function merely calls the actual implementation above and returns itself.
  626  *
  627  * @param[in] filename File to load
  628  * @param[in] flags Flags you wish to set.
  629 */
  630 Mat imread( const String& filename, int flags )
  631  {
  632     CV_TRACE_FUNCTION();
  634     /// create the basic container




    

  635     Mat img;
  637     /// load the data
  638     imread_( filename, flags, img );
  640     /// return a reference to the data
  641     return img;
  642  }
  644 void imread( const String& filename, OutputArray dst, int flags )
  645  {
  646     CV_TRACE_FUNCTION();
  648     Mat img = dst.getMat();
  650     /// load the data
  651     imread_(filename, flags, img);
  652  }
  654 /**
  655 * Read a multi-page image
  656 *
  657 *  This function merely calls the actual implementation above and returns itself.
  658 *
  659 * @param[in] filename File to load
  660 * @param[in] mats Reference to C++ vector<Mat> object to hold the images
  661 * @param[in] flags Flags you wish to set.
  662 *
  663 */
  664 bool imreadmulti(const String& filename, std::vector<Mat>& mats, int flags)
  665  {
  666     CV_TRACE_FUNCTION();
  668     return imreadmulti_(filename, flags, mats, 0, -1);
  669  }
  672 bool imreadmulti(const String& filename, std::vector<Mat>& mats, int start, int count, int flags)
  673  {
  674     CV_TRACE_FUNCTION();
  676     return imreadmulti_(filename, flags, mats, start, count);
  677  }
  679 static
  680 size_t imcount_(const String& filename, int flags)
  681  {
  682     try {
  683         ImageCollection collection(filename, flags);
  684         return collection.size();
  685      } catch(cv::Exception const& e)  {
  686         // Reading header or finding decoder for the filename is failed
  687         CV_LOG_ERROR(NULL, "imcount_('" << filename << "'): can't read header or can't find decoder: " << e.what());
  688      }
  689     return 0;
  690  }
  692 size_t imcount(const String& filename, int flags)
  693  {
  694     CV_TRACE_FUNCTION();
  696     return imcount_(filename, flags);
  697  }
  700 static bool imwrite_( const String& filename, const std::vector<Mat>& img_vec,
  701                       const std::vector<int>& params_, bool flipv )
  702  {
  703     bool isMultiImg = img_vec.size() > 1;
  704     std::vector<Mat> write_vec;
  706     ImageEncoder encoder = findEncoder( filename );
  707     if( !encoder )
  708         CV_Error( Error::StsError, "could not find a writer for the specified extension" );
  710     for (size_t page = 0; page < img_vec.size(); page++)
  711      {
  712         Mat image = img_vec[page];
  713         CV_Assert(!image.empty());
  715         CV_Assert( image.channels() == 1 || image.channels() == 3 || image.channels() == 4 );
  717         Mat temp;
  718         if( !encoder->isFormatSupported(image.depth()) )
  719          {
  720             CV_Assert( encoder->isFormatSupported(CV_8U) );
  721             image.convertTo( temp, CV_8U );
  722             image = temp;
  723          }
  725         if( flipv )
  726          {
  727             flip(image, temp, 0);
  728             image = temp;
  729          }
  731         write_vec.push_back(image);
  732      }
  734     encoder->setDestination( filename );
  735 #if CV_VERSION_MAJOR < 5 && defined(HAVE_IMGCODEC_HDR)
  736     bool fixed = false;
  737     std::vector<int> params_pair(2);
  738     if (dynamic_cast<HdrEncoder*>(encoder.get()))
  739      {
  740         if (params_.size() == 1)
  741          {
  742             CV_LOG_WARNING(NULL, "imwrite() accepts key-value pair of parameters, but single value is passed. "
  743                                  "HDR encoder behavior has been changed, please use IMWRITE_HDR_COMPRESSION key.");
  744             params_pair[0] =




    
 IMWRITE_HDR_COMPRESSION;
  745             params_pair[1] = params_[0];
  746             fixed = true;
  747          }
  748      }
  749     const std::vector<int>& params = fixed ? params_pair : params_;
  750 #else
  751     const std::vector<int>& params = params_;
  752 #endif
  754     CV_Check(params.size(), (params.size() & 1) == 0, "Encoding 'params' must be key-value pairs");
  755     CV_CheckLE(params.size(), (size_t)(CV_IO_MAX_IMAGE_PARAMS*2), "");
  756     bool code = false;
  757     try
  758      {
  759         if (!isMultiImg)
  760             code = encoder->write( write_vec[0], params );
  761         else
  762             code = encoder->writemulti( write_vec, params ); //to be implemented
  764         if (!code)
  765          {
  766             FILE* f = fopen( filename.c_str(), "wb" );
  767             if ( !f )
  768              {
  769                 if (errno == EACCES)
  770                  {
  771                     CV_LOG_WARNING(NULL, "imwrite_('" << filename << "'): can't open file for writing: permission denied");
  772                  }
  773              }
  774             else
  775              {
  776                 fclose(f);
  777                 remove(filename.c_str());
  778              }
  779          }
  780      }
  781     catch (const cv::Exception& e)
  782      {
  783         CV_LOG_ERROR(NULL, "imwrite_('" << filename << "'): can't write data: " << e.what());
  784      }
  785     catch (...)
  786      {
  787         CV_LOG_ERROR(NULL, "imwrite_('" << filename << "'): can't write data: unknown exception");
  788      }
  790     return code;
  791  }
  793 bool imwrite( const String& filename, InputArray _img,
  794               const std::vector<int>& params )
  795  {
  796     CV_TRACE_FUNCTION();
  798     CV_Assert(!_img.empty());
  800     std::vector<Mat> img_vec;
  801     if (_img.isMatVector() || _img.isUMatVector())
  802         _img.getMatVector(img_vec);
  803     else
  804         img_vec.push_back(_img.getMat());
  806     CV_Assert(!img_vec.empty());
  807     return imwrite_(filename, img_vec, params, false);
  808  }
  810 static bool
  811 imdecode_( const Mat& buf, int flags, Mat& mat )
  812  {
  813     CV_Assert(!buf.empty());
  814     CV_Assert(buf.isContinuous());
  815     CV_Assert(buf.checkVector(1, CV_8U) > 0);
  816     Mat buf_row = buf.reshape(1, 1);  // decoders expects single row, avoid issues with vector columns
  818     String filename;
  820     ImageDecoder decoder = findDecoder(buf_row);
  821     if( !decoder )
  822         return false;
  824     int scale_denom = 1;
  825     if( flags > IMREAD_LOAD_GDAL )
  826      {
  827         if( flags & IMREAD_REDUCED_GRAYSCALE_2 )
  828             scale_denom = 2;
  829         else if( flags & IMREAD_REDUCED_GRAYSCALE_4 )
  830             scale_denom = 4;
  831         else if( flags & IMREAD_REDUCED_GRAYSCALE_8 )
  832             scale_denom = 8;
  833      }
  835     /// set the scale_denom in the driver
  836     decoder->setScale( scale_denom );
  838     if( !decoder->setSource(buf_row) )
  839      {
  840         filename = tempfile();
  841         FILE* f = fopen( filename.c_str(), "wb" );
  842         if( !f )
  843             return false;
  844         size_t bufSize = buf_row.total()*buf.elemSize();




    

  845         if (fwrite(buf_row.ptr(), 1, bufSize, f) != bufSize)
  846          {
  847             fclose( f );
  848             CV_Error( Error::StsError, "failed to write image data to temporary file" );
  849          }
  850         if( fclose(f) != 0 )
  851          {
  852             CV_Error( Error::StsError, "failed to write image data to temporary file" );
  853          }
  854         decoder->setSource(filename);
  855      }
  857     bool success = false;
  858     try
  859      {
  860         if (decoder->readHeader())
  861             success = true;
  862      }
  863     catch (const cv::Exception& e)
  864      {
  865         CV_LOG_ERROR(NULL, "imdecode_('" << filename << "'): can't read header: " << e.what());
  866      }
  867     catch (...)
  868      {
  869         CV_LOG_ERROR(NULL, "imdecode_('" << filename << "'): can't read header: unknown exception");
  870      }
  871     if (!success)
  872      {
  873         decoder.release();
  874         if (!filename.empty())
  875          {
  876             if (0 != remove(filename.c_str()))
  877              {
  878                 CV_LOG_WARNING(NULL, "unable to remove temporary file:" << filename);
  879              }
  880          }
  881         return false;
  882      }
  884     // established the required input image size
  885     Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
  887     int type = decoder->type();
  888     if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED )
  889      {
  890         if( (flags & IMREAD_ANYDEPTH) == 0 )
  891             type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
  893         if( (flags & IMREAD_COLOR) != 0 ||
  894            ((flags & IMREAD_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) )
  895             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
  896         else
  897             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
  898      }
  900     mat.create( size.height, size.width, type );
  902     success = false;
  903     try
  904      {
  905         if (decoder->readData(mat))
  906             success = true;
  907      }
  908     catch (const cv::Exception& e)
  909      {
  910         CV_LOG_ERROR(NULL, "imdecode_('" << filename << "'): can't read data: " << e.what());
  911      }
  912     catch (...)
  913      {
  914         CV_LOG_ERROR(NULL, "imdecode_('" << filename << "'): can't read data: unknown exception");
  915      }
  917     if (!filename.empty())
  918      {
  919         if (0 != remove(filename.c_str()))
  920          {
  921             CV_LOG_WARNING(NULL, "unable to remove temporary file: " << filename);
  922          }
  923      }
  925     if (!success)
  926      {
  927         return false;
  928      }
  930     if( decoder->setScale( scale_denom ) > 1 ) // if decoder is JpegDecoder then decoder->setScale always returns 1
  931      {
  932         resize(mat, mat, Size( size.width / scale_denom, size.height / scale_denom ), 0, 0, INTER_LINEAR_EXACT);
  933      }
  935     /// optionally rotate the data if EXIF' orientation flag says so
  936     if (!mat.empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED)
  937      {
  938         ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
  939      }
  941     return true;
  942  }
  945 Mat imdecode




    
( InputArray _buf, int flags )
  946  {
  947     CV_TRACE_FUNCTION();
  949     Mat buf = _buf.getMat(), img;
  950     if (!imdecode_(buf, flags, img))
  951         img.release();
  953     return img;
  954  }
  956 Mat imdecode( InputArray _buf, int flags, Mat* dst )
  957  {
  958     CV_TRACE_FUNCTION();
  960     Mat buf = _buf.getMat(), img;
  961     dst = dst ? dst : &img;
  962     if (imdecode_(buf, flags, *dst))
  963         return *dst;
  964     else
  965         return cv::Mat();
  966  }
  968 static bool
  969 imdecodemulti_(const Mat& buf, int flags, std::vector<Mat>& mats, int start, int count)
  970  {
  971     CV_Assert(!buf.empty());
  972     CV_Assert(buf.isContinuous());
  973     CV_Assert(buf.checkVector(1, CV_8U) > 0);
  974     Mat buf_row = buf.reshape(1, 1);  // decoders expects single row, avoid issues with vector columns
  976     String filename;
  978     ImageDecoder decoder = findDecoder(buf_row);
  979     if (!decoder)
  980         return 0;
  982     if (count < 0)  {
  983         count = std::numeric_limits<int>::max();
  984      }
  986     if (!decoder->setSource(buf_row))
  987      {
  988         filename = tempfile();
  989         FILE* f = fopen(filename.c_str(), "wb");
  990         if (!f)
  991             return 0;
  992         size_t bufSize = buf_row.total() * buf.elemSize();
  993         if (fwrite(buf_row.ptr(), 1, bufSize, f) != bufSize)
  994          {
  995             fclose(f);
  996             CV_Error(Error::StsError, "failed to write image data to temporary file");
  997          }
  998         if (fclose(f) != 0)
  999          {
 1000             CV_Error(Error::StsError, "failed to write image data to temporary file");
 1001          }
 1002         decoder->setSource(filename);
 1003      }
 1005     // read the header to make sure it succeeds
 1006     bool success = false;
 1007     try
 1008      {
 1009         // read the header to make sure it succeeds
 1010         if (decoder->readHeader())
 1011             success = true;
 1012      }
 1013     catch (const cv::Exception& e)
 1014      {
 1015         CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read header: " << e.what());
 1016      }
 1017     catch (...)
 1018      {
 1019         CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read header: unknown exception");
 1020      }
 1022     int current = start;
 1023     while (success && current > 0)
 1024      {
 1025         if (!decoder->nextPage())
 1026          {
 1027             success = false;
 1028             break;
 1029          }
 1030         --current;
 1031      }
 1033     if (!success)
 1034      {
 1035         decoder.release();
 1036         if (!filename.empty())
 1037          {
 1038             if (0 != remove(filename.c_str()))
 1039              {
 1040                 CV_LOG_WARNING(NULL, "unable to remove temporary file: " << filename);
 1041              }
 1042          }
 1043         return 0;
 1044      }
 1046     while (current < count)
 1047      {
 1048         // grab the decoded type
 1049         int type = decoder->type();
 1050         if ((flags & IMREAD_LOAD_GDAL) !=




    
 IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED)
 1051          {
 1052             if ((flags & IMREAD_ANYDEPTH) == 0)
 1053                 type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
 1055             if ((flags & IMREAD_COLOR) != 0 ||
 1056                 ((flags & IMREAD_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1))
 1057                 type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
 1058             else
 1059                 type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
 1060          }
 1062         // established the required input image size
 1063         Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
 1065         // read the image data
 1066         Mat mat(size.height, size.width, type);
 1067         success = false;
 1068         try
 1069          {
 1070             if (decoder->readData(mat))
 1071                 success = true;
 1072          }
 1073         catch (const cv::Exception& e)
 1074          {
 1075             CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read data: " << e.what());
 1076          }
 1077         catch (...)
 1078          {
 1079             CV_LOG_ERROR(NULL, "imreadmulti_('" << filename << "'): can't read data: unknown exception");
 1080          }
 1081         if (!success)
 1082             break;
 1084         // optionally rotate the data if EXIF' orientation flag says so
 1085         if ((flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED)
 1086          {
 1087             ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
 1088          }
 1090         mats.push_back(mat);
 1091         if (!decoder->nextPage())
 1092          {
 1093             break;
 1094          }
 1095         ++current;
 1096      }
 1098     if (!filename.empty())
 1099      {
 1100         if (0 != remove(filename.c_str()))
 1101          {
 1102             CV_LOG_WARNING(NULL, "unable to remove temporary file: " << filename);
 1103          }
 1104      }
 1106     if (!success)
 1107         mats.clear();
 1108     return !mats.empty();
 1109  }
 1111 bool imdecodemulti(InputArray _buf, int flags, CV_OUT std::vector<Mat>& mats, const Range& range)
 1112  {
 1113     CV_TRACE_FUNCTION();
 1115     Mat buf = _buf.getMat();
 1116     if (range == Range::all())
 1117      {
 1118         return imdecodemulti_(buf, flags, mats, 0, -1);
 1119      }
 1120     else
 1121      {
 1122         CV_CheckGE(range.start, 0, "Range start cannot be negative.");
 1123         CV_CheckGT(range.size(), 0, "Range cannot be empty.");
 1124         return imdecodemulti_(buf, flags, mats, range.start, range.size());
 1125      }
 1126  }
 1128 bool imencode( const String& ext, InputArray _image,
 1129                std::vector<uchar>& buf, const std::vector<int>& params_ )
 1130  {
 1131     CV_TRACE_FUNCTION();
 1133     Mat image = _image.getMat();
 1134     CV_Assert(!image.empty());
 1136     int channels = image.channels();
 1137     CV_Assert( channels == 1 || channels == 3 || channels == 4 );
 1139     ImageEncoder encoder = findEncoder( ext );
 1140     if( !encoder )
 1141         CV_Error( Error::StsError, "could not find encoder for the specified extension" );
 1143     if( !encoder->isFormatSupported(image.depth()) )
 1144      {
 1145         CV_Assert( encoder->isFormatSupported(CV_8U) );
 1146         Mat temp;
 1147         image.convertTo(temp,




    
 CV_8U);
 1148         image = temp;
 1149      }
 1151 #if CV_VERSION_MAJOR < 5 && defined(HAVE_IMGCODEC_HDR)
 1152     bool fixed = false;
 1153     std::vector<int> params_pair(2);
 1154     if (dynamic_cast<HdrEncoder*>(encoder.get()))
 1155      {
 1156         if (params_.size() == 1)
 1157          {
 1158             CV_LOG_WARNING(NULL, "imwrite() accepts key-value pair of parameters, but single value is passed. "
 1159                                  "HDR encoder behavior has been changed, please use IMWRITE_HDR_COMPRESSION key.");
 1160             params_pair[0] = IMWRITE_HDR_COMPRESSION;
 1161             params_pair[1] = params_[0];
 1162             fixed = true;
 1163          }
 1164      }
 1165     const std::vector<int>& params = fixed ? params_pair : params_;
 1166 #else
 1167     const std::vector<int>& params = params_;
 1168 #endif
 1170     CV_Check(params.size(), (params.size() & 1) == 0, "Encoding 'params' must be key-value pairs");
 1171     CV_CheckLE(params.size(), (size_t)(CV_IO_MAX_IMAGE_PARAMS*2), "");
 1173     bool code;
 1174     if( encoder->setDestination(buf) )
 1175      {
 1176         code = encoder->write(image, params);
 1177         encoder->throwOnEror();
 1178         CV_Assert( code );
 1179      }
 1180     else
 1181      {
 1182         String filename = tempfile();
 1183         code = encoder->setDestination(filename);
 1184         CV_Assert( code );
 1186         code = encoder->write(image, params);
 1187         encoder->throwOnEror();
 1188         CV_Assert( code );
 1190         FILE* f = fopen( filename.c_str(), "rb" );
 1191         CV_Assert(f != 0);
 1192         fseek( f, 0, SEEK_END );
 1193         long pos = ftell(f);
 1194         buf.resize((size_t)pos);
 1195         fseek( f, 0, SEEK_SET );
 1196         buf.resize(fread( &buf[0], 1, buf.size(), f ));
 1197         fclose(f);
 1198         remove(filename.c_str());
 1199      }
 1200     return code;
 1201  }
 1203 bool haveImageReader( const String& filename )
 1204  {
 1205     ImageDecoder decoder = cv::findDecoder(filename);
 1206     return !decoder.empty();
 1207  }
 1209 bool haveImageWriter( const String& filename )
 1210  {
 1211     cv::ImageEncoder encoder = cv::findEncoder(filename);
 1212     return !encoder.empty();
 1213  }
 1215 class ImageCollection::Impl  {
 1216 public:
 1217     Impl() = default;
 1218     Impl(const std::string&  filename, int flags);
 1219     void init(String const& filename, int flags);
 1220     size_t size() const;
 1221     Mat& at(int index);
 1222     Mat& operator[](int index);
 1223     void releaseCache(int index);
 1224     ImageCollection::iterator begin(ImageCollection* ptr);
 1225     ImageCollection::iterator end(ImageCollection* ptr);
 1226     Mat read();
 1227     int width() const;
 1228     int height() const;
 1229     bool readHeader();
 1230     Mat readData();
 1231     bool advance();
 1232     int currentIndex() const;
 1233     void reset();
 1235 private:
 1236     String m_filename;
 1237     int m_flags { };
 1238     std::size_t m_size { };
 1239     int m_width { };
 1240     int m_height { };
 1241 




    
    int m_current { };
 1242     std::vector<cv::Mat> m_pages;
 1243     ImageDecoder m_decoder;
 1244  };
 1246 ImageCollection::Impl::Impl(std::string const& filename, int flags)  {
 1247     this->init(filename, flags);
 1248  }
 1250 void ImageCollection::Impl::init(String const& filename, int flags)  {
 1251     m_filename = filename;
 1252     m_flags = flags;
 1254 #ifdef HAVE_GDAL
 1255     if (m_flags != IMREAD_UNCHANGED && (m_flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL)  {
 1256         m_decoder = GdalDecoder().newDecoder();
 1257      }
 1258     else  {
 1259 #endif
 1260     m_decoder = findDecoder(filename);
 1261 #ifdef HAVE_GDAL
 1262      }
 1263 #endif
 1266     CV_Assert(m_decoder);
 1267     m_decoder->setSource(filename);
 1268     CV_Assert(m_decoder->readHeader());
 1270     // count the pages of the image collection
 1271     size_t count = 1;
 1272     while(m_decoder->nextPage()) count++;
 1274     m_size = count;
 1275     m_pages.resize(m_size);
 1276     // Reinitialize the decoder because we advanced to the last page while counting the pages of the image
 1277 #ifdef HAVE_GDAL
 1278     if (m_flags != IMREAD_UNCHANGED && (m_flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL)  {
 1279         m_decoder = GdalDecoder().newDecoder();
 1280      }
 1281     else  {
 1282 #endif
 1283     m_decoder = findDecoder(m_filename);
 1284 #ifdef HAVE_GDAL
 1285      }
 1286 #endif
 1288     m_decoder->setSource(m_filename);
 1289     m_decoder->readHeader();
 1290  }
 1292 size_t ImageCollection::Impl::size() const  { return m_size;  }
 1294 Mat ImageCollection::Impl::read()  {
 1295     auto result = this->readHeader();
 1296     if(!result)  {
 1297         return  { };
 1298      }
 1299     return this->readData();
 1300  }
 1302 int ImageCollection::Impl::width() const  {
 1303     return m_width;
 1304  }
 1306 int ImageCollection::Impl::height() const  {
 1307     return m_height;
 1308  }
 1310 bool ImageCollection::Impl::readHeader()  {
 1311     bool status = m_decoder->readHeader();
 1312     m_width = m_decoder->width();
 1313     m_height = m_decoder->height();
 1314     return status;
 1315  }
 1317 // readHeader must be called before calling this method
 1318 Mat ImageCollection::Impl::readData()  {
 1319     int type = m_decoder->type();
 1320     if ((m_flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && m_flags != IMREAD_UNCHANGED)  {
 1321         if ((m_flags & IMREAD_ANYDEPTH) == 0)
 1322             type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
 1324         if ((m_flags & IMREAD_COLOR) != 0 ||
 1325             ((m_flags & IMREAD_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1))
 1326             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
 1327         else
 1328             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
 1329      }
 1331     // established the required input image size
 1332     Size size = validateInputImageSize(Size(m_width, m_height));
 1334     Mat mat(size.height, size.width, type);
 1335     bool success = false;
 1336     try  {
 1337         if (m_decoder->readData(mat))
 1338             success = true;
 1339      }
 1340     catch (const cv::Exception &e)  {
 1341         CV_LOG_ERROR(NULL, "ImageCollection class: can't read data: " << e.what());
 1342      }
 1343     catch (...)  {
 1344         CV_LOG_ERROR(NULL, "ImageCollection class:: can't read data: unknown exception");
 1345      }
 1346 




    
    if (!success)
 1347         return cv::Mat();
 1349     if ((m_flags & IMREAD_IGNORE_ORIENTATION) == 0 && m_flags != IMREAD_UNCHANGED)  {
 1350         ApplyExifOrientation(m_decoder->getExifTag(ORIENTATION), mat);
 1351      }
 1353     return mat;
 1354  }
 1356 bool ImageCollection::Impl::advance()  {  ++m_current; return m_decoder->nextPage();  }
 1358 int ImageCollection::Impl::currentIndex() const  { return m_current;  }
 1360 ImageCollection::iterator ImageCollection::Impl::begin(ImageCollection* ptr)  { return ImageCollection::iterator(ptr);  }
 1362 ImageCollection::iterator ImageCollection::Impl::end(ImageCollection* ptr)  { return ImageCollection::iterator(ptr, static_cast<int>(this->size()));  }
 1364 void ImageCollection::Impl::reset()  {
 1365     m_current = 0;
 1366 #ifdef HAVE_GDAL
 1367     if (m_flags != IMREAD_UNCHANGED && (m_flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL)  {
 1368         m_decoder = GdalDecoder().newDecoder();
 1369      }
 1370     else  {
 1371 #endif
 1372     m_decoder = findDecoder(m_filename);
 1373 #ifdef HAVE_GDAL
 1374      }
 1375 #endif
 1377     m_decoder->setSource(m_filename);
 1378     m_decoder->readHeader();
 1379  }
 1381 Mat& ImageCollection::Impl::at(int index)  {
 1382     CV_Assert(index >= 0 && size_t(index) < m_size);
 1383     return operator[](index);
 1384  }
 1386 Mat& ImageCollection::Impl::operator[](int index)  {
 1387     if(m_pages.at(index).empty())  {
 1388         // We can't go backward in multi images. If the page is not in vector yet,
 1389         // go back to first page and advance until the desired page and read it into memory
 1390         if(m_current != index)  {
 1391             reset();
 1392             for(int i = 0; i != index && advance(); ++i)  { }
 1393          }
 1394         m_pages[index] = read();
 1395      }
 1396     return m_pages[index];
 1397  }
 1399 void ImageCollection::Impl::releaseCache(int index)  {
 1400     CV_Assert(index >= 0 && size_t(index) < m_size);
 1401     m_pages[index].release();
 1402  }
 1404 /* ImageCollection API*/
 1406 ImageCollection::ImageCollection() : pImpl(new Impl())  { }
 1408 ImageCollection::ImageCollection(const std::string& filename, int flags) : pImpl(new Impl(filename, flags))  { }
 1410 void ImageCollection::init(const String& img, int flags)  { pImpl->init(img, flags);  }
 1412 size_t ImageCollection::size() const  { return pImpl->size();  }
 1414 const Mat& ImageCollection::at(int index)  { return pImpl->at(index);  }
 1416 const Mat& ImageCollection::operator[](int index)  { return pImpl->operator[](index);  }
 1418 void ImageCollection::releaseCache(int index)  { pImpl->releaseCache(index);  }
 1420 Ptr<ImageCollection::Impl> ImageCollection::getImpl()  { return pImpl;  }
 1422 /* Iterator API */
 1424 ImageCollection::iterator ImageCollection::begin()  { return pImpl->begin(this);  }
 1426 ImageCollection::iterator ImageCollection::end()  { return pImpl->end(this);  }
 1428 ImageCollection::iterator::iterator(ImageCollection* col) : m_pCollection(col), m_curr(0)  { }
 1430 ImageCollection::iterator::iterator(ImageCollection* col, int end) : m_pCollection(col), m_curr(end)  { }
 1432 Mat& ImageCollection::iterator::operator*()  {
 1433     CV_Assert(m_pCollection);
 1434     return m_pCollection->getImpl()->operator[](m_curr);
 1435  }
 1437 Mat* ImageCollection::iterator::operator->()  {
 1438     CV_Assert(m_pCollection);
 1439     return &m_pCollection->getImpl()->operator[](m_curr);
 1440  }
 1442 ImageCollection::iterator& ImageCollection::iterator::operator++()  {
 1443     if(m_pCollection->pImpl->currentIndex() == m_curr)  {
 1444         m_pCollection->pImpl->advance();
 1445      }
 1446     m_curr++;
 1447     return *this;
 1448  }
 1450 ImageCollection::iterator ImageCollection::iterator::operator++(int)  {
 1451     iterator tmp = *this;
 1452     ++(*this);
 1453     return tmp;
 1454  }