All files / core/src/utilities getPixelSpacingInformation.ts

62.5% Statements 20/32
50% Branches 11/22
75% Functions 3/4
62.5% Lines 20/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145        428x                                           18x   18x   18x                     18x                                                   18x     18x                                                         2380x 2380x   2380x             2380x     2380x         2380x                 34338x   34338x 2380x     31958x   31958x 18x     31940x            
import { isEqual } from './isEqual';
import { CalibrationTypes } from '../enums';
 
// TODO: Use ENUMS from dcmjs
const projectionRadiographSOPClassUIDs = new Set([
  '1.2.840.10008.5.1.4.1.1.1', //	CR Image Storage
  '1.2.840.10008.5.1.4.1.1.1.1', //	Digital X-Ray Image Storage – for Presentation
  '1.2.840.10008.5.1.4.1.1.1.1.1', //	Digital X-Ray Image Storage – for Processing
  '1.2.840.10008.5.1.4.1.1.1.2', //	Digital Mammography X-Ray Image Storage – for Presentation
  '1.2.840.10008.5.1.4.1.1.1.2.1', //	Digital Mammography X-Ray Image Storage – for Processing
  '1.2.840.10008.5.1.4.1.1.1.3', //	Digital Intra – oral X-Ray Image Storage – for Presentation
  '1.2.840.10008.5.1.4.1.1.1.3.1', //	Digital Intra – oral X-Ray Image Storage – for Processing
  '1.2.840.10008.5.1.4.1.1.12.1', //	X-Ray Angiographic Image Storage
  '1.2.840.10008.5.1.4.1.1.12.1.1', //	Enhanced XA Image Storage
  '1.2.840.10008.5.1.4.1.1.12.2', //	X-Ray Radiofluoroscopic Image Storage
  '1.2.840.10008.5.1.4.1.1.12.2.1', //	Enhanced XRF Image Storage
  '1.2.840.10008.5.1.4.1.1.12.3', // X-Ray Angiographic Bi-plane Image Storage	Retired
]);
 
function calculateRadiographicPixelSpacing(instance) {
  const {
    PixelSpacing,
    ImagerPixelSpacing,
    EstimatedRadiographicMagnificationFactor,
    PixelSpacingCalibrationType,
    PixelSpacingCalibrationDescription,
  } = instance;
 
  const isProjection = true;
 
  Iif (!ImagerPixelSpacing) {
    // If only Pixel Spacing is present, and this is a projection radiograph,
    // PixelSpacing should be used, but the user should be informed that
    // what it means is unknown
    return {
      PixelSpacing,
      type: CalibrationTypes.UNKNOWN,
      isProjection,
    };
  }
 
  Iif (!PixelSpacing) {
    if (!EstimatedRadiographicMagnificationFactor) {
      console.warn(
        'EstimatedRadiographicMagnificationFactor was not present. Unable to correct ImagerPixelSpacing.'
      );
 
      return {
        PixelSpacing: ImagerPixelSpacing,
        type: CalibrationTypes.PROJECTION,
        isProjection,
      };
    }
    // Note that in IHE Mammo profile compliant displays, the value of Imager Pixel Spacing is required to be corrected by
    // Estimated Radiographic Magnification Factor and the user informed of that.
    // TODO: should this correction be done before all of this logic?
    const correctedPixelSpacing = ImagerPixelSpacing.map(
      (pixelSpacing) => pixelSpacing / EstimatedRadiographicMagnificationFactor
    );
 
    return {
      PixelSpacing: correctedPixelSpacing,
      type: CalibrationTypes.ERMF,
      isProjection,
    };
  }
 
  Eif (isEqual(PixelSpacing, ImagerPixelSpacing)) {
    // If Imager Pixel Spacing and Pixel Spacing are present and they have the same values,
    // then the user should be informed that the measurements are at the detector plane
    return {
      PixelSpacing,
      type: CalibrationTypes.PROJECTION,
      isProjection,
    };
  }
 
  if (PixelSpacingCalibrationType || PixelSpacingCalibrationDescription) {
    // If Imager Pixel Spacing and Pixel Spacing are present and they have different values,
    // then the user should be informed that these are "calibrated"
    return {
      PixelSpacing,
      type: CalibrationTypes.CALIBRATED,
      isProjection,
      PixelSpacingCalibrationType,
      PixelSpacingCalibrationDescription,
    };
  }
 
  // PixelSpacing should be used, but the user should be informed that
  // what it means is unknown
  return {
    PixelSpacing,
    type: CalibrationTypes.UNKNOWN,
    isProjection,
  };
}
 
function calculateUSPixelSpacing(instance) {
  const { SequenceOfUltrasoundRegions } = instance;
  const isArrayOfSequences = Array.isArray(SequenceOfUltrasoundRegions);
 
  Iif (isArrayOfSequences && SequenceOfUltrasoundRegions.length > 1) {
    console.warn(
      'Sequence of Ultrasound Regions > one entry. This is not yet implemented, all measurements will be shown in pixels.'
    );
    return;
  }
 
  const { PhysicalDeltaX, PhysicalDeltaY } = isArrayOfSequences
    ? SequenceOfUltrasoundRegions[0]
    : SequenceOfUltrasoundRegions;
  const USPixelSpacing = [
    Math.abs(PhysicalDeltaX) * 10,
    Math.abs(PhysicalDeltaY) * 10,
  ];
 
  return {
    PixelSpacing: USPixelSpacing,
  };
}
 
export default function getPixelSpacingInformation(instance) {
  // See http://gdcm.sourceforge.net/wiki/index.php/Imager_Pixel_Spacing
  // TODO: Add manual calibration
 
  const { PixelSpacing, SOPClassUID, SequenceOfUltrasoundRegions } = instance;
 
  if (SequenceOfUltrasoundRegions) {
    return calculateUSPixelSpacing(instance);
  }
 
  const isProjection = projectionRadiographSOPClassUIDs.has(SOPClassUID);
 
  if (isProjection) {
    return calculateRadiographicPixelSpacing(instance);
  }
 
  return {
    PixelSpacing,
    type: CalibrationTypes.NOT_APPLICABLE,
    isProjection: false,
  };
}