mirror of
https://github.com/opencv/opencv.git
synced 2025-08-06 14:36:36 +08:00
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
This commit is contained in:
parent
a53582d706
commit
fcaeeac931
@ -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);
|
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.
|
/** @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
|
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
|
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
|
/// Search for the relevant decoder to handle the imagery
|
||||||
ImageDecoder decoder;
|
ImageDecoder decoder;
|
||||||
|
|
||||||
|
CV_CheckGE(start, 0, "Start index cannont be < 0");
|
||||||
|
|
||||||
#ifdef HAVE_GDAL
|
#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();
|
decoder = GdalDecoder().newDecoder();
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
#endif
|
#endif
|
||||||
decoder = findDecoder(filename);
|
decoder = findDecoder(filename);
|
||||||
#ifdef HAVE_GDAL
|
#ifdef HAVE_GDAL
|
||||||
@ -521,10 +515,14 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// if no decoder was found, return nothing.
|
/// if no decoder was found, return nothing.
|
||||||
if (!decoder){
|
if (!decoder) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (count < 0) {
|
||||||
|
count = std::numeric_limits<int>::max();
|
||||||
|
}
|
||||||
|
|
||||||
/// set the filename in the driver
|
/// set the filename in the driver
|
||||||
decoder->setSource(filename);
|
decoder->setSource(filename);
|
||||||
|
|
||||||
@ -532,7 +530,7 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// read the header to make sure it succeeds
|
// read the header to make sure it succeeds
|
||||||
if( !decoder->readHeader() )
|
if (!decoder->readHeader())
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
catch (const cv::Exception& e)
|
catch (const cv::Exception& e)
|
||||||
@ -546,11 +544,22 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;)
|
int current = start;
|
||||||
|
|
||||||
|
while (current > 0)
|
||||||
|
{
|
||||||
|
if (!decoder->nextPage())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
--current;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (current < count)
|
||||||
{
|
{
|
||||||
// grab the decoded type
|
// grab the decoded type
|
||||||
int type = decoder->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)
|
if ((flags & IMREAD_ANYDEPTH) == 0)
|
||||||
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
|
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
|
||||||
@ -585,7 +594,7 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// optionally rotate the data if EXIF' orientation flag says so
|
// 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);
|
ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
|
||||||
}
|
}
|
||||||
@ -595,6 +604,7 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
++current;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !mats.empty();
|
return !mats.empty();
|
||||||
@ -636,9 +646,81 @@ bool imreadmulti(const String& filename, std::vector<Mat>& mats, int flags)
|
|||||||
{
|
{
|
||||||
CV_TRACE_FUNCTION();
|
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,
|
static bool imwrite_( const String& filename, const std::vector<Mat>& img_vec,
|
||||||
const std::vector<int>& params, bool flipv )
|
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());
|
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
|
#endif
|
||||||
|
|
||||||
}} // namespace
|
}} // namespace
|
||||||
|
Loading…
Reference in New Issue
Block a user