Skip to content

Comments

[GSoC] Add GIF decode and encode for imgcodecs#25691

Merged
asmorkalov merged 25 commits intoopencv:4.xfrom
redhecker:gifSupport
Dec 7, 2024
Merged

[GSoC] Add GIF decode and encode for imgcodecs#25691
asmorkalov merged 25 commits intoopencv:4.xfrom
redhecker:gifSupport

Conversation

@redhecker
Copy link
Contributor

@redhecker redhecker commented Jun 2, 2024

this is related to #24855

we add gif support for imread, imreadmulti, imwrite and imwritemulti

opencv_extra: opencv/opencv_extra#1203

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

@sturkmen72
Copy link
Contributor

test_imgcodecs fails
probably you need to rename your repositories

https://github.com/redhecker/opencv-GSoC24 -> https://github.com/redhecker/opencv
https://github.com/redhecker/opencv_extra-GSoC24 -> https://github.com/redhecker/opencv_extra

@redhecker
Copy link
Contributor Author

test_imgcodecs fails probably you need to rename your repositories

https://github.com/redhecker/opencv-GSoC24 -> https://github.com/redhecker/opencv
https://github.com/redhecker/opencv_extra-GSoC24 -> https://github.com/redhecker/opencv_extra

i've already done this, then how to rerun the build bot? or do i need to start a new pull request?

@sturkmen72
Copy link
Contributor

sturkmen72 commented Jun 2, 2024

just add a new commit.

for example you can write some information here
https://github.com/redhecker/opencv/blob/4.x/modules/imgcodecs/include/opencv2/imgcodecs.hpp#L287

/** @brief Loads images from the specified file into a vector of Mat objects. 

The function imreadmulti loads images from the specified file into a vector of Mat objects.
if the file is one of supported multi-page file formats, all images will be loaded. Otherwise one image will be loaded.

Currently, the following file formats are supported:

-   GIF files - \*.gif (always supported)
-   AVIF - \*.avif (see the *Note* section)
-   TIFF files - \*.tiff, \*.tif (see the *Note* section)

@param filename Name of file to be loaded.
@param mats A vector of Mat objects holding each page.
@param flags Flag that can take values of cv::ImreadModes, default with cv::IMREAD_ANYCOLOR.
@sa cv::imread
*/

@asmorkalov asmorkalov requested a review from vrabaud June 3, 2024 09:12
@asmorkalov asmorkalov changed the title [GSoC]Add GIF decode for imgcodecs [GSoC] Add GIF decode for imgcodecs Jun 3, 2024
@asmorkalov asmorkalov added this to the 4.11.0 milestone Jun 3, 2024
@vrabaud
Copy link
Contributor

vrabaud commented Jun 3, 2024

You need to update the CMake code to take GIF into account. The best is probably to have a look at how it's done for AVIF.

@vrabaud
Copy link
Contributor

vrabaud commented Jun 3, 2024

Thx for the code. I'd recommend to wait for the animation API that @sturkmen72 will during the GSoC.
*multi is for multipage images, e.g. TIFF, and not animations.

@redhecker redhecker requested review from asmorkalov and vrabaud July 6, 2024 01:01
Copy link
Contributor

@vrabaud vrabaud left a comment

Choose a reason for hiding this comment

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

The biggest issue I see is with transparency: it seems not be handled properly. There should be an option to apply the background color or not (which would therefore return cv::Mat4b)

redhecker and others added 4 commits July 27, 2024 18:33
Co-authored-by: TrendMYX <trendmyx@126.com>
Co-authored-by: TrendMYX <trendmyx@126.com>
@redhecker redhecker changed the title [GSoC] Add GIF decode for imgcodecs [GSoC] Add GIF decode and encode for imgcodecs Aug 21, 2024
redhecker and others added 2 commits August 27, 2024 17:43
@asmorkalov
Copy link
Contributor

@vrabaud What is the current PR status? Is it ready for integration? Please list issues, if not.

@asmorkalov asmorkalov merged commit 082cd7a into opencv:4.x Dec 7, 2024
@sturkmen72
Copy link
Contributor

@redhecker could you check this file https://upload.wikimedia.org/wikipedia/commons/d/d3/Newtons_cradle_animation_book_2.gif
imreadmulti and imreadanimation fails to load all frames

@sturkmen72
Copy link
Contributor

take a look at the source of file only the file above is problematic
https://commons.wikimedia.org/wiki/File:Newtons_cradle_animation_book_2.gif

@redhecker
Copy link
Contributor Author

@redhecker could you check this file https://upload.wikimedia.org/wikipedia/commons/d/d3/Newtons_cradle_animation_book_2.gif imreadmulti and imreadanimation fails to load all frames

ok, i will try to fix this as soon as possible

@sturkmen72
Copy link
Contributor

in bool GifDecoder::getFrameCount_()

m_frame_count ++; reaches 9

imcount("d:/github/Newtons_cradle_animation_book_2.gif") returns 9

@redhecker
Copy link
Contributor Author

in bool GifDecoder::getFrameCount_()

m_frame_count ++; reaches 9

imcount("d:/github/Newtons_cradle_animation_book_2.gif") returns 9

wait, when i run the following codes, i got 36 as output? i don't think i fully understand what you mean, do you mean you get 9 as output with the folling codes?

#include <opencv2/opencv.hpp>
#include <bits/stdc++.h>
int main() {
    std::cout << cv::imcount("Newtons_cradle_animation_book_2.gif") << std::endl;
}

but this cannot work for imreadmulti and imreadanimation. i think it's somewhere else that are wrong

@sturkmen72
Copy link
Contributor

in bool GifDecoder::getFrameCount_()
m_frame_count ++; reaches 9
imcount("d:/github/Newtons_cradle_animation_book_2.gif") returns 9

wait, when i run the following codes, i got 36 as output? i don't think i fully understand what you mean, do you mean you get 9 as output with the folling codes?

#include <opencv2/opencv.hpp>
#include <bits/stdc++.h>
int main() {
    std::cout << cv::imcount("Newtons_cradle_animation_book_2.gif") << std::endl;
}

but this cannot work for imreadmulti and imreadanimation. i think it's somewhere else that are wrong

sorry my bad.. you are right. i accidentally overwrite the image only readed frames when testing.

@sturkmen72
Copy link
Contributor

hasRead = lzwDecode(); // hasRead is false at 10th frame
https://github.com/opencv/opencv/blob/4.x/modules/imgcodecs/src/grfmt_gif.cpp#L149

@redhecker redhecker mentioned this pull request Jan 8, 2025
6 tasks
@redhecker
Copy link
Contributor Author

@sturkmen72 pls have a look at the newest pr, are there any other errors?

@sturkmen72
Copy link
Contributor

@redhecker well done! thank you.

asmorkalov pushed a commit that referenced this pull request Jan 11, 2025
Fix bugs in GIF decoding #26738 

### Pull Request Readiness Checklist

this is related to #25691 

i solved two bugs here:

1. the decoding setting:
according to [https://www.w3.org/Graphics/GIF/spec-gif89a.txt](https://www.w3.org/Graphics/GIF/spec-gif89a.txt)

```
    DEFERRED CLEAR CODE IN LZW COMPRESSION

    There has been confusion about where clear codes can be found in the
    data stream.  As the specification says, they may appear at anytime.  There
    is not a requirement to send a clear code when the string table is full.

    It is the encoder's decision as to when the table should be cleared.  When
    the table is full, the encoder can chose to use the table as is, making no
    changes to it until the encoder chooses to clear it.  The encoder during
    this time sends out codes that are of the maximum Code Size.

    As we can see from the above, when the decoder's table is full, it must
    not change the table until a clear code is received.  The Code Size is that
    of the maximum Code Size.  Processing other than this is done normally.

    Because of a large base of decoders that do not handle the decompression in
    this manner, we ask developers of GIF encoding software to NOT implement
    this feature until at least January 1991 and later if they see that their
    particular market is not ready for it.  This will give developers of GIF
    decoding software time to implement this feature and to get it into the
    hands of their clients before the decoders start "breaking" on the new
    GIF's.  It is not required that encoders change their software to take
    advantage of the deferred clear code, but it is for decoders.
```
at first i didn't consider this case, thus leads to a bug discussed in #25691. the changes made in function lzwDecode() is aiming at solving this.

2. the fetch method of loopCount:
in the codes at https://github.com/opencv/opencv/blob/4.x/modules/imgcodecs/src/grfmt_gif.cpp#L410, if the branch is taken, 3 more bytes will be taken, leading to unpredictable behavior.

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
- [ ] 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
JSpencerPittman pushed a commit to JSpencerPittman/opencv that referenced this pull request Jan 13, 2025
Fix bugs in GIF decoding opencv#26738 

### Pull Request Readiness Checklist

this is related to opencv#25691 

i solved two bugs here:

1. the decoding setting:
according to [https://www.w3.org/Graphics/GIF/spec-gif89a.txt](https://www.w3.org/Graphics/GIF/spec-gif89a.txt)

```
    DEFERRED CLEAR CODE IN LZW COMPRESSION

    There has been confusion about where clear codes can be found in the
    data stream.  As the specification says, they may appear at anytime.  There
    is not a requirement to send a clear code when the string table is full.

    It is the encoder's decision as to when the table should be cleared.  When
    the table is full, the encoder can chose to use the table as is, making no
    changes to it until the encoder chooses to clear it.  The encoder during
    this time sends out codes that are of the maximum Code Size.

    As we can see from the above, when the decoder's table is full, it must
    not change the table until a clear code is received.  The Code Size is that
    of the maximum Code Size.  Processing other than this is done normally.

    Because of a large base of decoders that do not handle the decompression in
    this manner, we ask developers of GIF encoding software to NOT implement
    this feature until at least January 1991 and later if they see that their
    particular market is not ready for it.  This will give developers of GIF
    decoding software time to implement this feature and to get it into the
    hands of their clients before the decoders start "breaking" on the new
    GIF's.  It is not required that encoders change their software to take
    advantage of the deferred clear code, but it is for decoders.
```
at first i didn't consider this case, thus leads to a bug discussed in opencv#25691. the changes made in function lzwDecode() is aiming at solving this.

2. the fetch method of loopCount:
in the codes at https://github.com/opencv/opencv/blob/4.x/modules/imgcodecs/src/grfmt_gif.cpp#L410, if the branch is taken, 3 more bytes will be taken, leading to unpredictable behavior.

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
- [ ] 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
JSpencerPittman pushed a commit to JSpencerPittman/opencv that referenced this pull request Jan 13, 2025
Fix bugs in GIF decoding opencv#26738 

### Pull Request Readiness Checklist

this is related to opencv#25691 

i solved two bugs here:

1. the decoding setting:
according to [https://www.w3.org/Graphics/GIF/spec-gif89a.txt](https://www.w3.org/Graphics/GIF/spec-gif89a.txt)

```
    DEFERRED CLEAR CODE IN LZW COMPRESSION

    There has been confusion about where clear codes can be found in the
    data stream.  As the specification says, they may appear at anytime.  There
    is not a requirement to send a clear code when the string table is full.

    It is the encoder's decision as to when the table should be cleared.  When
    the table is full, the encoder can chose to use the table as is, making no
    changes to it until the encoder chooses to clear it.  The encoder during
    this time sends out codes that are of the maximum Code Size.

    As we can see from the above, when the decoder's table is full, it must
    not change the table until a clear code is received.  The Code Size is that
    of the maximum Code Size.  Processing other than this is done normally.

    Because of a large base of decoders that do not handle the decompression in
    this manner, we ask developers of GIF encoding software to NOT implement
    this feature until at least January 1991 and later if they see that their
    particular market is not ready for it.  This will give developers of GIF
    decoding software time to implement this feature and to get it into the
    hands of their clients before the decoders start "breaking" on the new
    GIF's.  It is not required that encoders change their software to take
    advantage of the deferred clear code, but it is for decoders.
```
at first i didn't consider this case, thus leads to a bug discussed in opencv#25691. the changes made in function lzwDecode() is aiming at solving this.

2. the fetch method of loopCount:
in the codes at https://github.com/opencv/opencv/blob/4.x/modules/imgcodecs/src/grfmt_gif.cpp#L410, if the branch is taken, 3 more bytes will be taken, leading to unpredictable behavior.

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
- [ ] 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
@asmorkalov asmorkalov mentioned this pull request Jan 15, 2025
shyama7004 pushed a commit to shyama7004/opencv that referenced this pull request Jan 20, 2025
Fix bugs in GIF decoding opencv#26738 

### Pull Request Readiness Checklist

this is related to opencv#25691 

i solved two bugs here:

1. the decoding setting:
according to [https://www.w3.org/Graphics/GIF/spec-gif89a.txt](https://www.w3.org/Graphics/GIF/spec-gif89a.txt)

```
    DEFERRED CLEAR CODE IN LZW COMPRESSION

    There has been confusion about where clear codes can be found in the
    data stream.  As the specification says, they may appear at anytime.  There
    is not a requirement to send a clear code when the string table is full.

    It is the encoder's decision as to when the table should be cleared.  When
    the table is full, the encoder can chose to use the table as is, making no
    changes to it until the encoder chooses to clear it.  The encoder during
    this time sends out codes that are of the maximum Code Size.

    As we can see from the above, when the decoder's table is full, it must
    not change the table until a clear code is received.  The Code Size is that
    of the maximum Code Size.  Processing other than this is done normally.

    Because of a large base of decoders that do not handle the decompression in
    this manner, we ask developers of GIF encoding software to NOT implement
    this feature until at least January 1991 and later if they see that their
    particular market is not ready for it.  This will give developers of GIF
    decoding software time to implement this feature and to get it into the
    hands of their clients before the decoders start "breaking" on the new
    GIF's.  It is not required that encoders change their software to take
    advantage of the deferred clear code, but it is for decoders.
```
at first i didn't consider this case, thus leads to a bug discussed in opencv#25691. the changes made in function lzwDecode() is aiming at solving this.

2. the fetch method of loopCount:
in the codes at https://github.com/opencv/opencv/blob/4.x/modules/imgcodecs/src/grfmt_gif.cpp#L410, if the branch is taken, 3 more bytes will be taken, leading to unpredictable behavior.

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
- [ ] 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
NanQin555 pushed a commit to NanQin555/opencv that referenced this pull request Feb 24, 2025
[GSoC] Add GIF decode and encode for imgcodecs opencv#25691

this is related to opencv#24855 

we add  gif support for `imread`, `imreadmulti`, `imwrite` and `imwritemulti`

opencv_extra: opencv/opencv_extra#1203

### 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.
- [ ] The feature is well documented and sample code can be built with the project CMake
NanQin555 pushed a commit to NanQin555/opencv that referenced this pull request Feb 24, 2025
Fix bugs in GIF decoding opencv#26738 

### Pull Request Readiness Checklist

this is related to opencv#25691 

i solved two bugs here:

1. the decoding setting:
according to [https://www.w3.org/Graphics/GIF/spec-gif89a.txt](https://www.w3.org/Graphics/GIF/spec-gif89a.txt)

```
    DEFERRED CLEAR CODE IN LZW COMPRESSION

    There has been confusion about where clear codes can be found in the
    data stream.  As the specification says, they may appear at anytime.  There
    is not a requirement to send a clear code when the string table is full.

    It is the encoder's decision as to when the table should be cleared.  When
    the table is full, the encoder can chose to use the table as is, making no
    changes to it until the encoder chooses to clear it.  The encoder during
    this time sends out codes that are of the maximum Code Size.

    As we can see from the above, when the decoder's table is full, it must
    not change the table until a clear code is received.  The Code Size is that
    of the maximum Code Size.  Processing other than this is done normally.

    Because of a large base of decoders that do not handle the decompression in
    this manner, we ask developers of GIF encoding software to NOT implement
    this feature until at least January 1991 and later if they see that their
    particular market is not ready for it.  This will give developers of GIF
    decoding software time to implement this feature and to get it into the
    hands of their clients before the decoders start "breaking" on the new
    GIF's.  It is not required that encoders change their software to take
    advantage of the deferred clear code, but it is for decoders.
```
at first i didn't consider this case, thus leads to a bug discussed in opencv#25691. the changes made in function lzwDecode() is aiming at solving this.

2. the fetch method of loopCount:
in the codes at https://github.com/opencv/opencv/blob/4.x/modules/imgcodecs/src/grfmt_gif.cpp#L410, if the branch is taken, 3 more bytes will be taken, leading to unpredictable behavior.

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
- [ ] 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
param.push_back(7);
param.push_back(IMWRITE_GIF_DITHER);
param.push_back(2);
EXPECT_NO_THROW(imencode(".png", img_gt, buff, param));
Copy link
Contributor

Choose a reason for hiding this comment

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

@redhecker is there something like forgotten issue here ?
EXPECT_NO_THROW(imencode(".gif", img_gt, buff, param)); fails

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that there's something wrong here, where ".png" used with gif params. However, the code was written by @TrendMYX , i think he will fix it in a few days.

Copy link
Contributor

Choose a reason for hiding this comment

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

@redhecker @TrendMYX fyi

[ERROR:0@0.088] global loadsave.cpp:1687 cv::imencodeWithMetadata imencode(): can't encode data: OpenCV(4.13.0-dev) C:\build\precommit_windows64\4.x\opencv\modules\imgcodecs\src\grfmt_gif.cpp:1022: error: (-215:Assertion failed) false in function 'cv::GifEncoder::ditheringKernel'

Exception message: OpenCV(4.13.0-dev) C:\build\precommit_windows64\4.x\opencv\modules\imgcodecs\src\loadsave.cpp:1274: error: (-215:Assertion failed) !buf.empty() in function 'cv::imdecode_'

Choose a reason for hiding this comment

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

@sturkmen72 @redhecker Sorry for all the mistakes. Here is the modified version which goes through successfully on my laptop.

TEST(Imgcodecs_Gif,write_gif_flags){
    //rows611 x cols293, three‑channel, constant value 1
    const int expected_rows = 611;
    const int expected_cols = 293;
    cv::Mat img_gt(expected_rows, expected_cols, CV_8UC3, cv::Scalar::all(1));
    //the encoding parameters
    std::vector<unsigned char> buff;
    std::vector<int> param;
    param.push_back(cv::IMWRITE_GIF_QUALITY);
    param.push_back(7);
    param.push_back(cv::IMWRITE_GIF_DITHER);
    param.push_back(2);
    //Encode part
    ASSERT_NO_THROW(cv::imencode(".gif", img_gt, buff, param));
    //Decode part
    cv::Mat img;
    ASSERT_NO_THROW(img = cv::imdecode(buff, cv::IMREAD_ANYCOLOR));
    ASSERT_FALSE(img.empty());

    EXPECT_EQ(img.cols, expected_cols);
    EXPECT_EQ(img.rows, expected_rows);
    EXPECT_EQ(img.type(), CV_8UC3);
    // Compare, maxdiff=16
    EXPECT_PRED_FORMAT2(cvtest::MatComparator(16, 0), img, img_gt);
}

Copy link
Contributor

Choose a reason for hiding this comment

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

@TrendMYX thank you. feel free to create a PR or i will do later.

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.

8 participants