-
Notifications
You must be signed in to change notification settings - Fork 21
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
Use libjpeg-turbo for all Lossless JPEG bit depths #105
base: master
Are you sure you want to change the base?
Conversation
Enabled by the solution to: libjpeg-turbo/libjpeg-turbo#768 (Planned to be included in libjpeg-turbo release 3.1.0.) There are still some Lossless JPEG encoded images that libjpeg-turbo refuses to decode, see the discussions in: * libjpeg-turbo/libjpeg-turbo#586 * libjpeg-turbo/libjpeg-turbo#765
be98be3
to
830f680
Compare
This is WIP and will stay as a draft pull request until there's an official libjpeg-turbo release that includes the changes necessary. |
Thanks. I am aware of the ongoing work in libjpeg-turbo. Note that the JPEG codec in imagecodecs switches to the LJPEG codec for bit-depths not supported by libjpeg-turbo. |
Yes, |
The tests fail due to the issue discussed here: libjpeg-turbo/libjpeg-turbo#765
@@ -109,7 +109,7 @@ | |||
- `libheif <https://github.com/strukturag/libheif>`_ 1.17.6 | |||
(`libde265 <https://github.com/strukturag/libde265>`_ 1.0.15, | |||
`x265 <https://bitbucket.org/multicoreware/x265_git/src/master/>`_ 3.6) | |||
- `libjpeg-turbo <https://github.com/libjpeg-turbo/libjpeg-turbo>`_ 3.0.3 | |||
- `libjpeg-turbo <https://github.com/libjpeg-turbo/libjpeg-turbo>`_ 6ec8e41f50e5a83fe078732cbf0360272165ed45 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the latest sha1 from the dev branch. No official release tag.
I tested this with a 16bit Lossless JPEG file as input: import sys
from imagecodecs import imread, jpeg8_decode, jpeg8_encode
from numpy.testing import assert_array_equal
filename = sys.argv[1]
image = imread(filename)
if image.ndim > 2:
image = image[..., 0].copy() # copy to fix strides
for bit_depth in range(16, 1, -1):
print(bit_depth)
if bit_depth <= 8 and image.itemsize > 1:
# FIXME: Should this really be necessary?
image = image.astype("u1")
enc = jpeg8_encode(
image,
lossless=True,
predictor=1,
bitspersample=bit_depth,
)
dec = jpeg8_decode(enc)
assert_array_equal(image, dec)
image <<= 1 It works, but the case with bit-depth <= 8 in a uint16 array should be handled in a better way. EDIT: Fixed this with the check here. |
And improve error handling.
@@ -141,7 +141,7 @@ def jpeg8_encode( | |||
(src.dtype == numpy.uint8 or src.dtype == numpy.uint16) | |||
and src.ndim in {2, 3} | |||
# src.nbytes <= 2147483647 and # limit to 2 GB | |||
and samples in {1, 3, 4} | |||
and samples in {1, 2, 3, 4} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to work as expected with 2 components:
import sys
from imagecodecs import imread, jpeg8_decode, jpeg8_encode
from numpy.testing import assert_array_equal
filename = sys.argv[1]
image = imread(filename)
enc = jpeg8_encode(
image,
lossless=True,
predictor=1,
bitspersample=16,
)
dec = jpeg8_decode(enc)
assert_array_equal(image, dec)
These files were created by a Lossless JPEG encoder (implemented by me...) that contained a bug that caused the largest Huffman code to contain all ones. There's no problem to decode these images (even for libjpeg-turbo, see the discussion in libjpeg-turbo/libjpeg-turbo#765 ) but libjpeg-turbo refuses to do since they are not valid according to the JPEG spec. Now I recreated them using jpeg8_encode. dng0.ljp was not a valid file.
(I replaced the broken dng*.ljp files that were created using my broken Lossless JPEG encoder.) I did a quick benchmark comparing Everything seems to work as expected now, but I guess we should wait for an official libjpeg-turbo tag. |
|
@SimonSegerblomRex What do you get if you use thorfdbg/libjpeg ? |
With thorfdbg/libjpeg I get:
and that's probably the right thing. The images decoded by lj92 and libjpeg-turbo are completely broken, so they would have been better off failing as well than trying to decode garbage. |
I found that lj92 fails to decode MARCONI_MxTWin-12-MONO2-JpegLossless-ZeroLengthSQ.dcm (just 0s out) while libjpeg-turbo decodes it without issues 👍 EDIT: Extracting and repairing the JPEG file using |
What kind of command did you use ?
|
EDIT: Using the output from First I just used this script to extract the JPEG file: import re
import struct
import sys
SOI = struct.pack(">H", 0xFFD8)
SOF3 = struct.pack(">H", 0xFFC3)
EOI = struct.pack(">H", 0xFFD9)
with open(sys.argv[1], "rb") as f:
data = f.read()
matches = re.finditer(b"(?=(" + SOI + b".*?" + SOF3 + b".+?" + EOI + b"))", data, re.S)
for i, match in enumerate(matches):
with open(f"{i}.jpg", "wb") as f:
print(i)
f.write(match.group(1)) It seems like |
This is ready for code review (but there's still no new libjpeg-turbo release or tag). |
Thank you. I will review this when libjpeg-turbo 3.1 is released. |
Enabled by the solution to libjpeg-turbo/libjpeg-turbo#768
(Planned to be included in libjpeg-turbo release 3.1.0.)
There are still some Lossless JPEG encoded images that libjpeg-turbo refuses to decode, see the discussions in:
Note to self while testing with local copy of libjpeg-turbo:
Put this in the
customize_build
function used bysetup.py
:and make sure to set
before running any python script importing imagecodecs.