*/
CV_EXPORTS_W bool imreadmulti(const String& filename, CV_OUT std::vector<Mat>& mats, int flags = IMREAD_ANYCOLOR);
+/** @brief Loads a of images of a multi-page image from a file.
+
+The function imreadmulti loads a specified range from a multi-page image from the specified file into a vector of Mat objects.
+@param filename Name of file to be loaded.
+@param start Start index of the image to load
+@param count Count number of images to load
+@param flags Flag that can take values of cv::ImreadModes, default with cv::IMREAD_ANYCOLOR.
+@param mats A vector of Mat objects holding each page, if more than one.
+@sa cv::imread
+*/
+CV_EXPORTS_W bool imreadmulti(const String& filename, CV_OUT std::vector<Mat>& mats, int start, int count, int flags = IMREAD_ANYCOLOR);
+
+/** @brief Returns the number of images inside the give file
+
+The function imcount will return the number of pages in a multi-page image, or 1 for single-page images
+@param filename Name of file to be loaded.
+@param flags Flag that can take values of cv::ImreadModes, default with cv::IMREAD_ANYCOLOR.
+*/
+CV_EXPORTS_W size_t imcount(const String& filename, int flags = IMREAD_ANYCOLOR);
+
/** @brief Saves an image to a specified file.
The function imwrite saves the image to the specified file. The image format is chosen based on the
}
-/**
-* Read an image into memory and return the information
-*
-* @param[in] filename File to load
-* @param[in] flags Flags
-* @param[in] mats Reference to C++ vector<Mat> object to hold the images
-*
-*/
static bool
-imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
+imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats, int start, int count)
{
/// Search for the relevant decoder to handle the imagery
ImageDecoder decoder;
+ CV_CheckGE(start, 0, "Start index cannont be < 0");
+
#ifdef HAVE_GDAL
- if (flags != IMREAD_UNCHANGED && (flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL){
+ if (flags != IMREAD_UNCHANGED && (flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL) {
decoder = GdalDecoder().newDecoder();
}
- else{
+ else {
#endif
decoder = findDecoder(filename);
#ifdef HAVE_GDAL
#endif
/// if no decoder was found, return nothing.
- if (!decoder){
+ if (!decoder) {
return 0;
}
+ if (count < 0) {
+ count = std::numeric_limits<int>::max();
+ }
+
/// set the filename in the driver
decoder->setSource(filename);
try
{
// read the header to make sure it succeeds
- if( !decoder->readHeader() )
+ if (!decoder->readHeader())
return 0;
}
catch (const cv::Exception& e)
return 0;
}
- for (;;)
+ int current = start;
+
+ while (current > 0)
+ {
+ if (!decoder->nextPage())
+ {
+ return false;
+ }
+ --current;
+ }
+
+ while (current < count)
{
// grab the decoded type
int type = decoder->type();
- if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED )
+ if ((flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED)
{
if ((flags & IMREAD_ANYDEPTH) == 0)
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
break;
// optionally rotate the data if EXIF' orientation flag says so
- if( (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
+ if ((flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED)
{
ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
}
{
break;
}
+ ++current;
}
return !mats.empty();
{
CV_TRACE_FUNCTION();
- return imreadmulti_(filename, flags, mats);
+ return imreadmulti_(filename, flags, mats, 0, -1);
}
+
+bool imreadmulti(const String& filename, std::vector<Mat>& mats, int start, int count, int flags)
+{
+ CV_TRACE_FUNCTION();
+
+ return imreadmulti_(filename, flags, mats, start, count);
+}
+
+static
+size_t imcount_(const String& filename, int flags)
+{
+ /// Search for the relevant decoder to handle the imagery
+ ImageDecoder decoder;
+
+#ifdef HAVE_GDAL
+ if (flags != IMREAD_UNCHANGED && (flags & IMREAD_LOAD_GDAL) == IMREAD_LOAD_GDAL) {
+ decoder = GdalDecoder().newDecoder();
+ }
+ else {
+#else
+ CV_UNUSED(flags);
+#endif
+ decoder = findDecoder(filename);
+#ifdef HAVE_GDAL
+ }
+#endif
+
+ /// if no decoder was found, return nothing.
+ if (!decoder) {
+ return 0;
+ }
+
+ /// set the filename in the driver
+ decoder->setSource(filename);
+
+ // read the header to make sure it succeeds
+ try
+ {
+ // read the header to make sure it succeeds
+ if (!decoder->readHeader())
+ return 0;
+ }
+ catch (const cv::Exception& e)
+ {
+ std::cerr << "imcount_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
+ return 0;
+ }
+ catch (...)
+ {
+ std::cerr << "imcount_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
+ return 0;
+ }
+
+ size_t result = 1;
+
+
+ while (decoder->nextPage())
+ {
+ ++result;
+ }
+
+ return result;
+}
+
+size_t imcount(const String& filename, int flags)
+{
+ CV_TRACE_FUNCTION();
+
+ return imcount_(filename, flags);
+}
+
+
static bool imwrite_( const String& filename, const std::vector<Mat>& img_vec,
const std::vector<int>& params, bool flipv )
{
EXPECT_EQ(CV_8UC3, img.type()) << cv::typeToString(img.type());
}
+TEST(Imgcodecs_Tiff, count_multipage)
+{
+ const string root = cvtest::TS::ptr()->get_data_path();
+ {
+ const string filename = root + "readwrite/multipage.tif";
+ ASSERT_EQ((size_t)6, imcount(filename));
+ }
+ {
+ const string filename = root + "readwrite/test32FC3_raw.tiff";
+ ASSERT_EQ((size_t)1, imcount(filename));
+ }
+}
+
+TEST(Imgcodecs_Tiff, read_multipage_indexed)
+{
+ const string root = cvtest::TS::ptr()->get_data_path();
+ const string filename = root + "readwrite/multipage.tif";
+ const string page_files[] = {
+ "readwrite/multipage_p1.tif",
+ "readwrite/multipage_p2.tif",
+ "readwrite/multipage_p3.tif",
+ "readwrite/multipage_p4.tif",
+ "readwrite/multipage_p5.tif",
+ "readwrite/multipage_p6.tif"
+ };
+ const int page_count = sizeof(page_files) / sizeof(page_files[0]);
+ vector<Mat> single_pages;
+ for (int i = 0; i < page_count; i++)
+ {
+ // imread and imreadmulti have different default values for the flag
+ const Mat page = imread(root + page_files[i], IMREAD_ANYCOLOR);
+ single_pages.push_back(page);
+ }
+ ASSERT_EQ((size_t)page_count, single_pages.size());
+
+ {
+ SCOPED_TRACE("Edge Cases");
+ vector<Mat> multi_pages;
+ bool res = imreadmulti(filename, multi_pages, 0, 0);
+ // If we asked for 0 images and we successfully read 0 images should this be false ?
+ ASSERT_TRUE(res == false);
+ ASSERT_EQ((size_t)0, multi_pages.size());
+ res = imreadmulti(filename, multi_pages, 0, 123123);
+ ASSERT_TRUE(res == true);
+ ASSERT_EQ((size_t)6, multi_pages.size());
+ }
+
+ {
+ SCOPED_TRACE("Read all with indices");
+ vector<Mat> multi_pages;
+ bool res = imreadmulti(filename, multi_pages, 0, 6);
+ ASSERT_TRUE(res == true);
+ ASSERT_EQ((size_t)page_count, multi_pages.size());
+ for (int i = 0; i < page_count; i++)
+ {
+ EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), multi_pages[i], single_pages[i]);
+ }
+ }
+
+ {
+ SCOPED_TRACE("Read one by one");
+ vector<Mat> multi_pages;
+ for (int i = 0; i < page_count; i++)
+ {
+ bool res = imreadmulti(filename, multi_pages, i, 1);
+ ASSERT_TRUE(res == true);
+ ASSERT_EQ((size_t)1, multi_pages.size());
+ EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), multi_pages[0], single_pages[i]);
+ multi_pages.clear();
+ }
+ }
+
+ {
+ SCOPED_TRACE("Read multiple at a time");
+ vector<Mat> multi_pages;
+ for (int i = 0; i < page_count/2; i++)
+ {
+ bool res = imreadmulti(filename, multi_pages, i*2, 2);
+ ASSERT_TRUE(res == true);
+ ASSERT_EQ((size_t)2, multi_pages.size());
+ EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), multi_pages[0], single_pages[i * 2]) << i;
+ EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), multi_pages[1], single_pages[i * 2 + 1]);
+ multi_pages.clear();
+ }
+ }
+}
+
+
#endif
}} // namespace