Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Example: Lossless and Near-Lossless JPEG-LS

This example creates one deterministic 96 × 96, 12-bit medical-style phantom. It encodes and decodes the same image twice through RITK’s public native API: lossless NEAR = 0 and near-lossless NEAR = 3.

The first three panels deliberately use the same [0, 4095] display range. That makes their anatomy directly comparable, but an error of at most three gray levels is difficult to see across a 12-bit range. The fourth panel solves that visibility problem: it displays abs(near_lossless - source) on [0, 3]. It is an error map, not another contrast-stretched anatomy image.

The metrics below the panels are computed from the arrays that are rendered:

  • the lossless mismatch count is an exact equality oracle and must be zero;
  • each encoded size is the actual returned stream length;
  • changed-sample count reports how many near-lossless values differ; and
  • maximum absolute error must be no greater than the declared NEAR = 3.

Source and command

Source: crates/ritk-codecs/examples/book_jpeg_ls.rs

cargo run -p ritk-codecs --example book_jpeg_ls -- \
  docs/book/figures/jpeg_ls_codec.svg

The example fails instead of writing a misleading figure if lossless reconstruction differs at any sample, near-lossless error exceeds NEAR, the near-lossless path produces a degenerate all-zero error map, malformed input does not return PixelCountMismatch, or any rendered array disagrees with the declared geometry.

Adapt the workflow

let stream = encode_grayscale_jpeg_ls(
    &samples,
    rows,
    columns,
    bits_stored,
    near,
)?;

let reconstructed = decode_jpeg_ls_fragment(
    &stream,
    PixelLayout {
        rows: usize::try_from(rows)?,
        cols: usize::try_from(columns)?,
        samples_per_pixel: 1,
        bits_allocated: if bits_stored <= 8 { 8 } else { 16 },
        pixel_representation: PixelSignedness::Unsigned,
        rescale_slope: 1.0,
        rescale_intercept: 0.0,
    },
)?;

Use near = 0 when every stored integer must be preserved. A nonzero value permits a bounded per-sample change; whether that is clinically acceptable is a dataset and workflow policy outside the codec.