Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bundled SSIMULACRA2 detects differences in losslessly converted JXL #3594

Open
kylesacher opened this issue May 18, 2024 · 1 comment
Open

Comments

@kylesacher
Copy link

Describe the bug
Converting a PNG to a JXL with cjxl -d 0, and then comparing the original and converted images with ssimulacra2 results in a score < 100.

To Reproduce

  1. Use cjxl -d 0 to convert a PNG to a JXL (e.g. cjxl house.png house.jxl -d 0)
  2. Compare the original and converted image with ssimulacra2 (e.g. ssimulacra2 house.png house.jxl)
  3. Observe that the SSIMULACRA2 score is less than 100
  4. Convert back to PNG with djxl (e.g. djxl house.jxl house2.png)
  5. Compare the original PNG and new PNG with ssimulacra2 (e.g. ssimulacra2 house.png house2.png)
  6. Observe that the SSIMULACRA2 score is 100

Expected behavior
The SSIMULACRA2 score between the original PNG and converted JXL should be 100.

Screenshots
house
house jxl
house2

Environment

  • OS: Windows
  • Compiler version: N/A
  • CPU type: x86_64
  • cjxl/djxl version string: JPEG XL encoder v0.10.2 e148959 [AVX2,SSE2], JPEG XL decoder v0.10.2 e148959 [AVX2,SSE2]

Additional context

  • Only steps 1-3 are necessary to reproduce the problem. Steps 4-6 show that the data is not actually lost, despite the <100 score.
  • The attached house.png, house.jxl.png, and house2.png are the files used in the examples I've given in the steps to reproduce.
  • The exact score I got from SSIMULACRA2 was 96.67210224.
  • cjxl, djxl, and ssimulacra2 all came from jxl-x64-windows-static in release 0.10.2.
@jonsneyers
Copy link
Member

Thanks for noticing this problem!

Looks like this is caused by slight differences in the way the conversion from int to float is implemented in dec_modular.cc (which is what is used when decoding a jxl) and in enc_external_image.cc (which is what is used when decoding a png).

The discrepancy is very small (rounding one way or the other in float32, which corresponds to an off-by-one and occasional off-by-two in 24-bit integer precision), but it is enough to cause the ssimulacra2 score to be below 100.

When decoding the jxl back to 8-bit png, the discrepancy disappears since the error is way too small to lead to different 8-bit values. But ssimulacra2 works in the full float32 precision so it notices the small discrepancy.

This problem will disappear if one or both of these things is done:

  • refactor the implementation of int-to-float to avoid the near-duplication, so both code paths do it in exactly the same way
  • avoid the conversion to float after modular decoding, producing a uint8 ppf that will then be treated the same way as the decoded png

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants