# JPEG 2000 Encoding

The requirements for JPEG 2000 encoding are defined in Section 8.2.4 and Annex A.4.4 of Part 5 of the DICOM Standard. The JPEG 2000 compression scheme is defined by ISO/IEC 15444-1/ITU T.800 (the second link has free access).

The following JPEG 2000 encoding parameters are used by pylibjpeg plugin:

- For JPEG 2000 Lossless the reversible DWT 5-3 wavelet

- For JPEG 2000 the irreversible DWT 9-7 wavelet

- 6 DWT decomposition levels

- 64 x 64 code block size

- 1 tile

- LRCP progression order

- No sub-sampling

- No JP2 header

## Valid Image Pixel Parameters

The table below lists the valid Image Pixel module parameters for Pixel Data encoded using the JPEG 2000 Lossless or JPEG 2000 transfer syntaxes. For an explanation of each parameter and its relationship with the Pixel Data see the glossary of Image Pixel elements.

Samples per Pixel | Photometric Interpretation | Pixel Representation | Planar Configuration | Bits Allocated | Bits Stored
--- | --- | --- | --- | --- | ---
1 | MONOCHROME1 | 0 or 1 | (absent) | 8, 16, 24, 32 or 40 | 1 to 38
MONOCHROME2
PALETTE COLOR 1 | 0 | (absent) | 8 or 16 | 1 to 16
3 | RGB | 0 | 0 | 8, 16, 24, 32 or 40 | 1 to 38
YBR_RCT
YBR_ICT 2
YBR_FULL

1 JPEG 2000 Lossless only
2 JPEG 2000 only

### Photometric Interpretation

To ensure you have the correct Photometric Interpretation the uncompressed pixel data should already be in the corresponding color space:

- If your uncompressed pixel data is grayscale (intensity) based:

  - Use `MONOCHROME1` if the minimum intensity value should be displayed as white.

  - Use `MONOCHROME2` if the minimum intensity value should be displayed as black.

- If your uncompressed pixel data uses a single sample per pixel and is an index to the Red, Green and Blue Palette Color Lookup Tables:

  - Use `PALETTE COLOR`.

- If your uncompressed pixel data is in RGB color space:

  - For Photometric Interpretation `RGB`, `YBR_ICT` or `YBR_RCT`; nothing else is required.

  - For Photometric Interpretation `YBR_FULL` the pixel data must first be converted into RGB color space, however the conversion operation is lossy.

- If your uncompressed pixel data is in YCbCr color space:

  - For Photometric Interpretation `RGB`, `YBR_ICT` or `YBR_RCT`; the pixel data must first be converted into RGB color space, however the conversion operation is lossy.

  - For Photometric Interpretation `YBR_FULL` nothing else is required.

If your uncompressed pixel data is in RGB color space then setting the Photometric Interpretation to `YBR_ICT` or `YBR_RCT` will signal the encoder to apply multiple-component transformation (MCT) to the pixel data during the encoding process, which should result in a higher compression ratio for a given image quality. If you don’t wish to use MCT then keep the Photometric Interpretation as `RGB`

### Bits Stored

The maximum supported Bits Stored value for encoding is `24`.

## Examples

### JPEG 2000 Lossless

Losslessly compress unsigned RGB pixel data in-place, without the use of the multiple-component transformation:

    from pydicom import examples
    from pydicom.uid import JPE2000Lossless

    ds = examples.rgb_color
    assert ds.SamplesPerPixel == 1
    assert ds.PhotometricInterpretation == "RGB"
    assert ds.BitsAllocated == 8
    assert ds.BitsStored == 8
    assert ds.PixelRepresentation == 0
    assert len(ds.PixelData) == 921600

    ds.compress(JPE2000Lossless)

    print(len(ds.PixelData))  # ~334412

Losslessly compress unsigned RGB pixel data in-place with multiple-component transformation:

    from pydicom import examples
    from pydicom.uid import JPE2000Lossless

    ds = examples.rgb_color
    assert ds.SamplesPerPixel == 1
    assert ds.PhotometricInterpretation == "RGB"
    assert ds.BitsAllocated == 8
    assert ds.BitsStored == 8
    assert ds.PixelRepresentation == 0
    assert len(ds.PixelData) == 921600

    # YBR_ICT is not valid with *JPEG 2000 Lossless*
    ds.PhotometricInterpretation = "YBR_RCT"
    ds.compress(JPE2000Lossless)

    print(len(ds.PixelData))  # ~152342

Losslessly compress signed greyscale pixel data in-place:

    from pydicom import examples
    from pydicom.uid import JPE2000Lossless

    ds = examples.ct
    assert ds.SamplesPerPixel == 1
    assert ds.PhotometricInterpretation == 'MONOCHROME2'
    assert ds.BitsAllocated == 16
    assert ds.BitsStored == 16
    assert ds.PixelRepresentation == 1
    assert len(ds.PixelData) == 32768

    ds.compress(JPE2000Lossless)

    print(len(ds.PixelData))  # ~13656

### JPEG 2000

Warning

pydicom makes no recommendations for specifying image quality for lossy encoding methods. Any examples of lossy encoding are for illustration purposes only.

When performing lossy encoding one or more quality layers may be used, with each quality layer allowing the reconstruction of the pixel data at a given resolution. The image quality of each layer is controlled by passing either the j2k_cr or the j2k_psnr parameter to the `encoding function` as `list[float]`, where:

- j2k_cr: a list of the compression ratios to use for each quality layer. There must be at least one quality layer and the minimum allowable compression ratio is `1`. When using multiple quality layers they should be ordered in decreasing value from left to right:

      # 1 quality layer at 1.5:1
      j2k_cr = [1.5]

      # 2 quality layers at 5:1, and 2:1
      j2k_cr = [5, 2]

- j2k_psnr: a list of the peak signal-to-noise ratios (in dB) to use for each quality layer. There must be at least one quality layer and when using multiple quality layers they should be ordered in increasing value from left to right:

      # 1 quality layer
      j2k_psnr = [80]

      # 3 quality layers
      j2k_psnr = [80, 100, 200]

Lossy compression of unsigned RGB pixel data without multiple-component transformation:

    from pydicom import examples
    from pydicom.uid import JPEG2000

    ds = examples.rgb_color
    assert ds.SamplesPerPixel == 1
    assert ds.PhotometricInterpretation == 'RGB'
    assert ds.BitsAllocated == 8
    assert ds.BitsStored == 8
    assert ds.PixelRepresentation == 0
    assert len(ds.PixelData) == 921600

    ds.compress(JPEG2000, j2k_cr=[20])

    print(len(ds.PixelData))  # ~46100

Lossy compression of unsigned RGB pixel data with multiple-component transformation:

    from pydicom import examples
    from pydicom.uid import JPEG2000

    ds = examples.rgb_color
    assert ds.SamplesPerPixel == 1
    assert ds.PhotometricInterpretation == 'RGB'
    assert ds.BitsAllocated == 8
    assert ds.BitsStored == 8
    assert ds.PixelRepresentation == 0
    assert len(ds.PixelData) == 921600

    # YBR_RCT is not valid with lossy *JPEG 2000*
    ds.PhotometricInterpretation = "YBR_ICT"

    ds.compress(JPEG2000, j2k_cr=[20])

    print(len(ds.PixelData))  # ~46076

Lossy compression of signed greyscale pixel data:

    from pydicom import examples
    from pydicom.uid import JPEG2000

    ds = examples.ct
    assert ds.SamplesPerPixel == 1
    assert ds.PhotometricInterpretation == 'MONOCHROME2'
    assert ds.BitsAllocated == 16
    assert ds.BitsStored == 16
    assert ds.PixelRepresentation == 1
    assert len(ds.PixelData) == 32768

    ds.compress(JPEG2000, j2k_cr=[20])

    print(ds.PixelData)  # ~1582

## Available Plugins

### pylibjpeg

Encoder | Plugins
--- | ---
Name | Requires | Added
`JPEG2000LosslessEncoder` | pylibjpeg | numpy, pylibjpeg, pylibjpeg-openjpeg | v3.0
`JPEG2000Encoder`