All formats

glymur

LanguagePython 3
LicenseMIT
Repositorygithub.com/quintusdias/glymur
Documentationglymur.readthedocs.io
Depends onNumPy, lxml, Pillow; the OpenJPEG shared library (loaded with ctypes)
Read / writeyes / yes; JP2, J2K, JPX; full box access; HTJ2K decoding with a recent OpenJPEG

glymur reads JPEG 2000 into NumPy arrays and writes NumPy arrays to JPEG 2000. Image access uses array slicing: a step in the slice selects a lower resolution level, a range selects a region, and only the needed data is decoded. It also parses every JP2/JPX box, so you can read and add XML, XMP, ICC profiles, GeoJP2 and resolution boxes, and print the codestream markers.

glymur loads the OpenJPEG library at run time with ctypes; it doesn’t bundle it. Install OpenJPEG with your system package manager or conda.

Installation#

Shell
pip install glymur
# plus the OpenJPEG library:
sudo apt install libopenjp2-7     # Debian / Ubuntu
brew install openjpeg             # macOS
# or: conda install -c conda-forge glymur   (installs OpenJPEG too)

Basic usage: read and write#

Python
import glymur

jp2 = glymur.Jp2k("in.jp2")
print(jp2.shape)            # (rows, cols, components), e.g. (480, 640, 3)
image = jp2[:]              # full image as a NumPy array (uint8 or uint16)

# write a lossless JP2 from a NumPy array
glymur.Jp2k("copy.jp2", data=image)

How to read at reduced resolution or a region#

The step of a slice must be a power of 2; each factor of 2 drops one resolution level. Ranges decode only part of the image:

Python
import glymur

jp2 = glymur.Jp2k("big.jp2")
half = jp2[::2, ::2]               # half width and height
quarter = jp2[::4, ::4]
smallest = jp2[::-1, ::-1]         # lowest resolution level in the file
region = jp2[1000:2000, 500:1500]  # rows 1000-1999, columns 500-1499 at full resolution

How to write lossy JPEG 2000#

cratios gives one compression ratio per quality layer; psnr gives target PSNR values in dB. A final value of 1 (cratios) or 0 (psnr) adds a lossless layer:

Python
import glymur
import numpy as np

data = np.random.randint(0, 255, (512, 512, 3), dtype=np.uint8)

glymur.Jp2k("layers.jp2", data=data, cratios=[40, 20, 10], irreversible=True)
glymur.Jp2k("psnr.jp2", data=data, psnr=[30, 40, 50, 0])
glymur.Jp2k("tiled.jp2", data=data, tilesize=(256, 256), numres=6, prog="RPCL", plt=True)

Read only the first quality layer of a layered file with jp2.layer = 0 before slicing.

How to inspect JP2 boxes and metadata#

Python
import glymur

jp2 = glymur.Jp2k("in.jp2")
print(jp2)                      # all boxes and the main codestream header

for box in jp2.box:
    print(box.box_id)           # 'jP  ', 'ftyp', 'jp2h', 'xml ', 'uuid', 'jp2c' ...

c = jp2.get_codestream()        # parsed codestream header
print(c.segment[1])             # SIZ marker: image size, components, bit depths

The ICC profile, if present, is in the colr box inside jp2h; XMP is in a uuid box whose data attribute holds the parsed XML.

How to decode with multiple threads#

Python
import glymur

glymur.set_option("lib.num_threads", 4)
image = glymur.Jp2k("big.jp2")[:]

Tips#