Skip to content

imgcodecs: implement imencodemulti()#26211

Merged
asmorkalov merged 12 commits intoopencv:4.xfrom
Kumataro:fix26207
Oct 18, 2024
Merged

imgcodecs: implement imencodemulti()#26211
asmorkalov merged 12 commits intoopencv:4.xfrom
Kumataro:fix26207

Conversation

@Kumataro
Copy link
Copy Markdown
Contributor

Close #26207

Pull Request Readiness Checklist

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

  • I agree to contribute to the project under Apache 2 License.
  • 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
  • The PR is proposed to the proper branch
  • There is a reference to the original bug report and related work
  • 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

{
vector<Mat> imgs;
Mat img(100, 100, CV_8UC1);
imgs.push_back(img);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Kumataro could you test

   vector<Mat> imgs;
    Mat img(100, 100, CV_8UC1);
    imgs.push_back(img);
    imgs.push_back(img.clone());

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your comment ! I mistakenly thought that it was enough to support multiple images for imencode().

But it seems that encoding multiple images requests reading callback function. After appending it, it works well.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your comment ! I mistakenly thought that it was enough to support multiple images for imencode().

But it seems that encoding multiple images requests reading callback function. After appending it, it works well.

Thank you for your contribution. to me looks perfect.

Comment on lines 724 to 727
if( (!encoder->isFormatSupported(image.depth())) && (encoder->isFormatSupported(CV_8U)) )
{
CV_Assert( encoder->isFormatSupported(CV_8U) );
CV_LOG_ONCE_WARNING(NULL, "Unsupported depth image for selected encoder is fallbacked to CV_8U.");
image.convertTo( temp, CV_8U );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log is good, but we get U.B., if the encoder does not support CV_8U by some reason.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review. This change comes from #26211 (comment) .

If there are no problem, I agree with revert it.

        if( !encoder->isFormatSupported(image.depth() ) )
        {
            CV_LOG_ONCE_WARNING(NULL, "Unsupported depth image for selected encoder is fallbacked to CV_8U.");
            CV_Assert( encoder->isFormatSupported(CV_8U) );
            image.convertTo( temp, CV_8U );

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review, I fixed it.

@asmorkalov
Copy link
Copy Markdown
Contributor

@Kumataro Thanks a lot for the contribution! I hide the function implementation in cpp file and got rid of exceptions that are thrown outside of the function. The current image i/o contract is to be exception-safe and return bool status.


@param ext File extension that defines the output format. Must include a leading period.
@param img Image to be written.
@param img Image to be compressed.
Copy link
Copy Markdown
Contributor

@sturkmen72 sturkmen72 Oct 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Mat or vector of Mat) Image or Images to be compressed.

@asmorkalov imwrite() writes single and multiple images. AFAIK imwritemulti() is just for python. also imencode() behaves same as imwrite()

imwritemulti() definition is like

//! @brief multi-image overload for bindings
CV_WRAP static inline
bool imwritemulti(const String& filename, InputArrayOfArrays img,
                  const std::vector<int>& params = std::vector<int>())
{
    return imwrite(filename, img, params);
}

Copy link
Copy Markdown
Contributor

@sturkmen72 sturkmen72 Oct 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think imwritemulti() also be defined as CV_EXPORTS_W and needs documentation

>>> help(cv2.imwritemulti)
Help on built-in function imwritemulti:

imwritemulti(...)
    imwritemulti(filename, img[, params]) -> retval
    .

@Kumataro
Copy link
Copy Markdown
Contributor Author

I'm sorry some tests for AVIF are failed.
I'll analyze it later. Give me some time.

AVIF encoder called CV_CheckDepth() and exception is happened.
AVIF tests expects to it, but it is not able to be catched.

AVIF encoder calls CV_CheckType() with bit_depth == 6, img.depth() == CV_8U. cv::Exception will be thrown.

    CV_CheckType(
        img.type(),
        (bit_depth == 8 && img.depth() == CV_8U) ||
            ((bit_depth == 10 || bit_depth == 12) && img.depth() == CV_16U),
        "AVIF only supports bit depth of 8 with CV_8U input or "
        "bit depth of 10 or 12 with CV_16U input");

AVIF tests expect that cv::Exception throws. But they doesn't.

TEST_P(Imgcodecs_Avif_Image_EncodeDecodeSuite, imencode_imdecode) {
  const cv::Mat& img_original = get_img_original();
  ASSERT_FALSE(img_original.empty());

  // Encode.
  std::vector<unsigned char> buf;
  if (!IsBitDepthValid()) {
    EXPECT_THROW(cv::imencode(".avif", img_original, buf, encoding_params_),
                 cv::Exception);
    return;
  }

Maybe loadsave.cpp catches this exception, but it will not rethrow. So AVIF tests cannot catch.

    try {
        if (!isMultiImg)
            code = encoder->write(write_vec[0], params);
        else
            code = encoder->writemulti(write_vec, params);

        encoder->throwOnEror();
        CV_Assert( code );
    }
    catch (const cv::Exception& e)
    {
        CV_LOG_ERROR(NULL, "imencode(): can't encode data: " << e.what());
        code = false;
    }
    catch (...)
    {
        CV_LOG_ERROR(NULL, "imencode(): can't encode data: unknown exception");
        code = false;
    }

I think (1) updation AVIF tests to use return value instead of exception or (2) removing try and catch in loadsave.cpp is needed.

@asmorkalov
Copy link
Copy Markdown
Contributor

Yes, I changed the implementation that makes code exception safe. I propose to tune tests to handle status.

@asmorkalov
Copy link
Copy Markdown
Contributor

cc @vrabaud

@Kumataro
Copy link
Copy Markdown
Contributor Author

Thank you for your comment, and I fixed to use status code instead of catching exception.


/** @brief Encodes array of images into a memory buffer.

The function is analog of cv::imencode for in-memory multi-page images compression.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function is analog to cv::imencode for in-memory multi-page image compression.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your review, I fixed this comment.

@asmorkalov asmorkalov added this to the 4.11.0 milestone Oct 15, 2024
@asmorkalov asmorkalov self-assigned this Oct 15, 2024
TEST(Imgcodecs_EXR, imencode_regression_26207_extra)
{
// CV_8U is not supported depth for EXR Encoder.
cv::Mat src(100, 100, CV_8UC1);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose to initialize mat with some values: some color or random data. It's applicable for the all new tests.

  1. It makes test really deterministic
  2. It makes sanitizers happy.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your comment, and I agree with you !

I fixed it, and set const for their source images.

@asmorkalov asmorkalov merged commit 35dbf32 into opencv:4.x Oct 18, 2024
@asmorkalov asmorkalov mentioned this pull request Oct 23, 2024
ting-xin pushed a commit to ting-xin/opencv that referenced this pull request Nov 17, 2024
imgcodecs: implement imencodemulti() opencv#26211

Close opencv#26207
### Pull Request Readiness Checklist

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

- [x] I agree to contribute to the project under Apache 2 License.
- [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] The PR is proposed to the proper branch
- [x] 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.
- [x] The feature is well documented and sample code can be built with the project CMake
thewoz pushed a commit to CobbsLab/OPENCV that referenced this pull request Feb 13, 2025
imgcodecs: implement imencodemulti() opencv#26211

Close opencv#26207
### Pull Request Readiness Checklist

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

- [x] I agree to contribute to the project under Apache 2 License.
- [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] The PR is proposed to the proper branch
- [x] 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.
- [x] The feature is well documented and sample code can be built with the project CMake
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cv::imencode function fails writing vector<Mat>

4 participants