Merge pull request #24405 from kochanczyk:4.x

Extend the signature of imdecodemulti() #24405

(Edited after addressing Reviewers' comments.)

Add an argument to `imdecodemulti()` to enable optional selection of pages of multi-page images.

Be default, all pages are decoded. If used, the additional argument may specify a continuous selection of pages to decode.


### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [X] I agree to contribute to the project under Apache 2 License.
- [X] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Marek Kochanczyk 2023-10-30 09:58:08 +01:00 committed by GitHub
parent 617d7ff575
commit e9e6b1e22c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 9 deletions

View File

@ -337,8 +337,9 @@ See cv::imreadmulti for the list of supported formats and flags description.
@param buf Input array or vector of bytes.
@param flags The same flags as in cv::imread, see cv::ImreadModes.
@param mats A vector of Mat objects holding each page, if more than one.
@param range A continuous selection of pages.
*/
CV_EXPORTS_W bool imdecodemulti(InputArray buf, int flags, CV_OUT std::vector<Mat>& mats);
CV_EXPORTS_W bool imdecodemulti(InputArray buf, int flags, CV_OUT std::vector<Mat>& mats, const cv::Range& range = Range::all());
/** @brief Encodes an image into a memory buffer.

View File

@ -1095,12 +1095,21 @@ imdecodemulti_(const Mat& buf, int flags, std::vector<Mat>& mats, int start, int
return !mats.empty();
}
bool imdecodemulti(InputArray _buf, int flags, CV_OUT std::vector<Mat>& mats)
bool imdecodemulti(InputArray _buf, int flags, CV_OUT std::vector<Mat>& mats, const Range& range)
{
CV_TRACE_FUNCTION();
Mat buf = _buf.getMat();
return imdecodemulti_(buf, flags, mats, 0, -1);
if (range == Range::all())
{
return imdecodemulti_(buf, flags, mats, 0, -1);
}
else
{
CV_CheckGE(range.start, 0, "Range start cannot be negative.");
CV_CheckGT(range.size(), 0, "Range cannot be empty.");
return imdecodemulti_(buf, flags, mats, range.start, range.size());
}
}
bool imencode( const String& ext, InputArray _image,

View File

@ -965,7 +965,7 @@ TEST_P(Imgcodecs_Tiff_Modes, decode_multipage)
}
}
TEST_P(Imgcodecs_Tiff_Modes, decode_multipage_use_memory_buffer)
TEST_P(Imgcodecs_Tiff_Modes, decode_multipage_use_memory_buffer_all_pages)
{
const int mode = GetParam();
const string root = cvtest::TS::ptr()->get_data_path();
@ -984,13 +984,14 @@ TEST_P(Imgcodecs_Tiff_Modes, decode_multipage_use_memory_buffer)
FILE* fp = fopen(filename.c_str(), "rb");
ASSERT_TRUE(fp != NULL);
fseek(fp, 0, SEEK_END);
long pos = ftell(fp);
std::vector<uchar> buf;
buf.resize((size_t)pos);
const size_t file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
buf.resize(fread(&buf[0], 1, buf.size(), fp));
std::vector<uchar> buf(file_size);
const size_t actual_read = fread(&buf[0], 1, file_size, fp);
fclose(fp);
ASSERT_EQ(file_size, actual_read);
ASSERT_EQ(file_size, static_cast<size_t>(buf.size()));
bool res = imdecodemulti(buf, mode, pages);
ASSERT_TRUE(res == true);
@ -1002,6 +1003,60 @@ TEST_P(Imgcodecs_Tiff_Modes, decode_multipage_use_memory_buffer)
}
}
TEST_P(Imgcodecs_Tiff_Modes, decode_multipage_use_memory_buffer_selected_pages)
{
const int mode = GetParam();
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 size_t page_count = sizeof(page_files) / sizeof(page_files[0]);
FILE* fp = fopen(filename.c_str(), "rb");
ASSERT_TRUE(fp != NULL);
fseek(fp, 0, SEEK_END);
const size_t file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
std::vector<uchar> buf(file_size);
const size_t actual_read = fread(&buf[0], 1, file_size, fp);
fclose(fp);
ASSERT_EQ(file_size, actual_read);
ASSERT_EQ(file_size, static_cast<size_t>(buf.size()));
const Range range(1, page_count - 1);
ASSERT_GE(range.size(), 1);
vector<Mat> middle_pages_from_imread;
for (int page_i = range.start; page_i < range.end; page_i++)
{
const Mat page = imread(root + page_files[page_i], mode);
middle_pages_from_imread.push_back(page);
}
ASSERT_EQ(
static_cast<size_t>(range.size()),
static_cast<size_t>(middle_pages_from_imread.size())
);
vector<Mat> middle_pages_from_imdecodemulti;
const bool res = imdecodemulti(buf, mode, middle_pages_from_imdecodemulti, range);
ASSERT_TRUE(res == true);
EXPECT_EQ(middle_pages_from_imread.size(), middle_pages_from_imdecodemulti.size());
for (int i = 0, e = range.size(); i < e; i++)
{
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0),
middle_pages_from_imread[i],
middle_pages_from_imdecodemulti[i]);
}
}
const int all_modes[] =
{
IMREAD_UNCHANGED,