Getting started¶
Installation¶
JVol can be installed using Pip Installs Packages (PIP):
pip install git+https://github.com/fepegar/jvol.git
Let's install it in this notebook.
%%capture
%pip install git+https://github.com/fepegar/jvol.git
Usage¶
Let's first download some NIfTI data from the Colin 27 Average Brain 2008 MNI template.
%%bash
curl -O -s https://packages.bic.mni.mcgill.ca/mni-models/colin27/mni_colin27_2008_nifti.zip
unzip -q -o mni_colin27_2008_nifti.zip
ls -lh *.nii
-rw-r--r-- 1 runner docker 109M Jul 10 2012 colin27_cls_tal_hires.nii
-rw-r--r-- 1 runner docker 217M Jul 10 2012 colin27_pd_tal_hires.nii
-rw-r--r-- 1 runner docker 217M Jul 10 2012 colin27_t1_tal_hires.nii
-rw-r--r-- 1 runner docker 217M Jul 10 2012 colin27_t2_tal_hires.nii
We'll use the jvol
command to encode an existing image.
Use jvol --help
to get a full list of features of the CLI tool.
%%bash
jvol --help
Usage: jvol [OPTIONS] INPUT_PATH OUTPUT_PATH
Tool for converting medical images to and from JPEG-encoded volumes.
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ * input_path FILE [default: None] [required] │
│ * output_path FILE [default: None] [required] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --quality -q INTEGER RANGE Quality of the JPEG │
│ [1<=x<=100] encoding, between 1 and │
│ 100. │
│ [default: 60] │
│ --block-size -b INTEGER RANGE [x>=2] Size of the blocks to │
│ use for encoding. │
│ Quality is higher with │
│ larger blocks, but so │
│ is the file size. │
│ [default: 8] │
│ --verbose -v INTEGER Enable verbose logging. │
│ Use -vv for debug │
│ logging. │
│ [default: 0] │
│ --install-completion Install completion for │
│ the current shell. │
│ --show-completion Show completion for the │
│ current shell, to copy │
│ it or customize the │
│ installation. │
│ --help Show this message and │
│ exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
Let's encode an image with the default settings.
%%bash
jvol colin27_t1_tal_hires.nii colin27_t1_tal_hires.jvol
Let's use Python to check how we've done. We'll also install TorchIO to read some of the image metadata.
%%capture
%pip install "torchio[plot]"
from pathlib import Path
import numpy as np
import torchio as tio
from humanize import naturalsize
def compare_sizes(original_path: Path, compressed_path: Path) -> None:
def get_num_pixels(path):
return np.prod(tio.ScalarImage(path).shape)
num_pixels = get_num_pixels(original_path)
original_size = original_path.stat().st_size
original_bits_per_pixel = 8 * original_size / num_pixels
compressed_size = compressed_path.stat().st_size
compr_bits_per_pixel = 8 * compressed_size / num_pixels
compression_ratio = original_size / compressed_size
nat_orig = naturalsize(original_size)
nat_comp = naturalsize(compressed_size)
print(f"Original file size: {nat_orig} ({original_bits_per_pixel:.2f} bits/pixel)")
print(f"Compressed file size: {nat_comp} ({compr_bits_per_pixel:.2f} bits/pixel)")
print(f"Compression ratio: {compression_ratio:.1f}×")
nii_path = Path("colin27_t1_tal_hires.nii")
jvol_path = Path("colin27_t1_tal_hires.jvol")
compare_sizes(nii_path, jvol_path)
Original file size: 227.5 MB (32.00 bits/pixel) Compressed file size: 8.0 MB (1.12 bits/pixel) Compression ratio: 28.6×
Not bad! Let's compare with lossless compression.
%%bash
gzip -k -f colin27_t1_tal_hires.nii
nii_gz_path = Path("colin27_t1_tal_hires.nii.gz")
compare_sizes(nii_path, nii_gz_path)
Original file size: 227.5 MB (32.00 bits/pixel) Compressed file size: 103.0 MB (14.49 bits/pixel) Compression ratio: 2.2×
It seems that we're doing much better!
You might be wondering about the visual quality of the compressed image, compared to the original. Let's use TorchIO to visualize both images.
We'll need to convert the compressed image to a format that TorchIO can read.
We can use jvol
to decode the image back to NIfTI.
%%bash
jvol colin27_t1_tal_hires.jvol colin27_t1_tal_hires_from_jvol.nii
def compare_images(original_path: Path, compressed_path: Path) -> None:
original = tio.ScalarImage(original_path)
compressed = tio.ScalarImage(compressed_path)
both = tio.Subject({"Original": original, "Compressed": compressed})
both.plot(figsize=(10, 6))
from_jvol_path = Path("colin27_t1_tal_hires_from_jvol.nii")
compare_images(nii_path, from_jvol_path)
They look quite similar, so it seems that this amount of compression might be acceptable for certain applications. Can we push the compression ratio even further? Let's use a smaller quality setting.
%%bash
jvol colin27_t1_tal_hires.nii colin27_t1_tal_hires_low_quality.jvol --quality 5
Again, let's convert back so TorchIO can read it.
%%bash
jvol colin27_t1_tal_hires_low_quality.jvol colin27_t1_tal_hires_low_quality.nii
from_jvol_tiny_path = Path("colin27_t1_tal_hires_low_quality.nii")
compare_images(nii_path, from_jvol_tiny_path)
The artifacts are slightly noticeable this time, but the image is visually still very similar. Let's see how much we've compressed the original image.
jvol_tiny_path = Path("colin27_t1_tal_hires_low_quality.jvol")
compare_sizes(nii_path, jvol_tiny_path)
Original file size: 227.5 MB (32.00 bits/pixel) Compressed file size: 981.3 kB (0.14 bits/pixel) Compression ratio: 231.8×