"
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 }