Creating a Lower Limb Panoramic X-ray

Measurement of knee alignment is useful for diagnosis of arthritic conditions and for planning and evaluation of surgical interventions. Alignment is measured by the hip-knee-ankle ($HKA$) angle in standing, load bearing, x-ray images. The angle is defined by the femoral and tibial mechanical axes. The femoral axis is defined by the center of the femur head and the mid condylar point. The tibial axis is defined by the center of the tibial plateau to the center of the tibial plafond.

Hip-Knee-Ankle angle defined by the femoral mechanical axis (solid red line with dashed extension), and tibial mechanical axis (solid blue line).

The three stances defined by the $HKA$ angle are:

  1. Neutral alignment, $HKA=0^o$.
  2. Varus, bow-legged, $HKA<0^o$.
  3. Valgus, knock-kneed, $HKA>0^o$.

For additional information see:

  1. T. D. Cooke et al., "Frontal plane knee alignment: a call for standardized measurement", J Rheumatol. 2007.
  2. A. F. Kamath et al., "What is Varus or Valgus Knee Alignment?: A Call for a Uniform Radiographic Classification", Clin Orthop Relat Res. 2010.

For a robust estimate of the $HKA$ angle we would like to use a single image that contains the anatomy from the femoral head down to the ankle. Acquisition of such an image with standard x-ray imaging devices is not possible. It is achievable by acquiring multiple partially overlapping images and aligning, registering, them to the same coordinate system. The subject of this notebook.

This notebook is based in part on the work described in: "A marker-free registration method for standing X-ray panorama reconstruction for hip-knee-ankle axis deformity assessment", Y. K. Ben-Zikri, Z. Yaniv, K. Baum, C. A. Linte, Computer Methods in Biomechanics and Biomedical Engineering: Imaging & Visualization, DOI:10.1080/21681163.2018.1537859.

In [1]:
import SimpleITK as sitk
import numpy as np
import os.path
import copy

%matplotlib notebook
import gui
import matplotlib.pyplot as plt

#utility method that either downloads data from the Girder repository or
#if already downloaded returns the file name for reading from disk (cached data)
%run update_path_to_download_script
from downloaddata import fetch_data as fdata

Loading data

In [2]:
# Fetch all of the data associated with this example.
data_directory = os.path.dirname(fdata("leg_panorama/readme.txt"))

hip_image =  sitk.ReadImage(os.path.join(data_directory,'hip.mha'))
knee_image =  sitk.ReadImage(os.path.join(data_directory,'knee.mha'))
ankle_image =  sitk.ReadImage(os.path.join(data_directory,'ankle.mha'))

gui.multi_image_display2D([hip_image, knee_image, ankle_image], figure_size=(10,4));
Fetching leg_panorama/readme.txt