未验证 提交 fcaeeac9 编写于 作者: H Harald Scheirich 提交者: GitHub

Merge pull request #19780 from HarryDC:feature/index-multiimage-tiff

Add reading of specific images from multipage tiff

* Add reading of specific images from multipage tiff

* Fix build issues

* Add missing flag for gdal

* Fix unused param warning

* Remove duplicated code

* change public parameter type to int

* Fix warnings

* Fix parameter check
上级 a53582d7
......@@ -215,6 +215,26 @@ The function imreadmulti loads a multi-page image from the specified file into a
*/
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
......
......@@ -495,25 +495,19 @@ imread_( const String& filename, int flags, Mat& mat )
}
/**
* 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
......@@ -521,10 +515,14 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
#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);
......@@ -532,7 +530,7 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
try
{
// read the header to make sure it succeeds
if( !decoder->readHeader() )
if (!decoder->readHeader())
return 0;
}
catch (const cv::Exception& e)
......@@ -546,11 +544,22 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
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));
......@@ -585,7 +594,7 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
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);
}
......@@ -595,6 +604,7 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
{
break;
}
++current;
}
return !mats.empty();
......@@ -636,9 +646,81 @@ bool imreadmulti(const String& filename, std::vector<Mat>& mats, int flags)
{
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 )
{
......
......@@ -358,6 +358,94 @@ TEST(Imgcodecs_Tiff, decode_black_and_write_image_pr17275_default)
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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册