It looks like you can approximate the orientation of the patient: lying on back or side using the following code:

avg_image_orientations = np.array([
    0.61659826,  0.77685789, -0.12766521,
    -0.39722351,  0.16699159, -0.90234914])
image_orientation = np.array(d.ImageOrientationPatient)
y = np.dot(image_orientation[:3], avg_image_orientations[:3])
x = np.dot(image_orientation[:3], avg_image_orientations[3:])
angle = np.arctan2(y, x) / np.pi * 180 - 75

d is a DICOM image. If you plot a histogram of the values you can see that the studies divide into two groups and if you rotate the SAX images you see that indeed the LV appears to be in the same orientation in all images. I found that there are some variability inside a study.

Here are 120 studies after orientation

Here is the code to compute the magical avg_image_orientations vector


In [ ]:
import numpy as np

image_directions = []
image_orientations = []
for study in range(700):
    # read SAX slice=0 t=0 from every study
    img_fname = dicom_filename(study=study, s=0, t=0)
    d = dicom.read_file(img_fname)
    if d.PatientPosition != 'HFS':
        print study,d.PatientPosition
    image_orientations.append(d.ImageOrientationPatient)
    image_direction = np.cross(d.ImageOrientationPatient[:3],d.ImageOrientationPatient[3:])
    image_directions.append(image_direction)
    
image_directions = np.array(image_directions)
avg_image_direction = image_directions.mean(axis=0)

image_orientations = np.array(image_orientations)
avg_image_orientations = image_orientations.mean(axis=0)
avg_image_orientations[:3] /= np.sqrt(np.dot(avg_image_orientations[:3],avg_image_orientations[:3]))
avg_image_orientations[3:] /= np.sqrt(np.dot(avg_image_orientations[3:],avg_image_orientations[3:]))
avg_image_orientations[3:] = np.cross(np.cross(avg_image_orientations[:3],avg_image_orientations[3:]),avg_image_orientations[:3])