Skip to content

Commit

Permalink
Merge branch 'master' into issue-3595
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick D. Lloyd authored Aug 12, 2023
2 parents 3131c5b + 88ef7b7 commit b5b0435
Show file tree
Hide file tree
Showing 57 changed files with 1,234 additions and 120 deletions.
2 changes: 1 addition & 1 deletion commit.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b55518e08ec9c9ab23e74aa4987927d8d75ae909
5302e5b62be22eb503d4fe067b435f7934284c39
10 changes: 5 additions & 5 deletions extensions/cornerstone-dicom-rt/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone-dicom-rt",
"version": "3.7.0-beta.46",
"version": "3.7.0-beta.47",
"description": "DICOM RT read workflow",
"author": "OHIF",
"license": "MIT",
Expand Down Expand Up @@ -31,10 +31,10 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.46",
"@ohif/extension-cornerstone": "3.7.0-beta.46",
"@ohif/extension-default": "3.7.0-beta.46",
"@ohif/i18n": "3.7.0-beta.46",
"@ohif/core": "3.7.0-beta.47",
"@ohif/extension-cornerstone": "3.7.0-beta.47",
"@ohif/extension-default": "3.7.0-beta.47",
"@ohif/i18n": "3.7.0-beta.47",
"prop-types": "^15.6.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand Down
10 changes: 5 additions & 5 deletions extensions/cornerstone-dicom-seg/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone-dicom-seg",
"version": "3.7.0-beta.46",
"version": "3.7.0-beta.47",
"description": "DICOM SEG read workflow",
"author": "OHIF",
"license": "MIT",
Expand Down Expand Up @@ -31,10 +31,10 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.46",
"@ohif/extension-cornerstone": "3.7.0-beta.46",
"@ohif/extension-default": "3.7.0-beta.46",
"@ohif/i18n": "3.7.0-beta.46",
"@ohif/core": "3.7.0-beta.47",
"@ohif/extension-cornerstone": "3.7.0-beta.47",
"@ohif/extension-default": "3.7.0-beta.47",
"@ohif/i18n": "3.7.0-beta.47",
"prop-types": "^15.6.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand Down
10 changes: 5 additions & 5 deletions extensions/cornerstone-dicom-sr/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone-dicom-sr",
"version": "3.7.0-beta.46",
"version": "3.7.0-beta.47",
"description": "OHIF extension for an SR Cornerstone Viewport",
"author": "OHIF",
"license": "MIT",
Expand Down Expand Up @@ -32,10 +32,10 @@
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.46",
"@ohif/extension-cornerstone": "3.7.0-beta.46",
"@ohif/extension-measurement-tracking": "3.7.0-beta.46",
"@ohif/ui": "3.7.0-beta.46",
"@ohif/core": "3.7.0-beta.47",
"@ohif/extension-cornerstone": "3.7.0-beta.47",
"@ohif/extension-measurement-tracking": "3.7.0-beta.47",
"@ohif/ui": "3.7.0-beta.47",
"dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
Expand Down
6 changes: 3 additions & 3 deletions extensions/cornerstone/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone",
"version": "3.7.0-beta.46",
"version": "3.7.0-beta.47",
"description": "OHIF extension for Cornerstone",
"author": "OHIF",
"license": "MIT",
Expand Down Expand Up @@ -37,8 +37,8 @@
"@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.9.3",
"@ohif/core": "3.7.0-beta.46",
"@ohif/ui": "3.7.0-beta.46",
"@ohif/core": "3.7.0-beta.47",
"@ohif/ui": "3.7.0-beta.47",
"dcmjs": "^0.29.6",
"dicom-parser": "^1.8.21",
"hammerjs": "^2.0.8",
Expand Down
6 changes: 3 additions & 3 deletions extensions/default/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-default",
"version": "3.7.0-beta.46",
"version": "3.7.0-beta.47",
"description": "Common/default features and functionality for basic image viewing",
"author": "OHIF Core Team",
"license": "MIT",
Expand Down Expand Up @@ -30,8 +30,8 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.46",
"@ohif/i18n": "3.7.0-beta.46",
"@ohif/core": "3.7.0-beta.47",
"@ohif/i18n": "3.7.0-beta.47",
"dcmjs": "^0.29.5",
"dicomweb-client": "^0.10.2",
"prop-types": "^15.6.2",
Expand Down
1 change: 1 addition & 0 deletions extensions/default/src/Panels/PanelStudyBrowser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ function _mapDisplaySets(displaySets, thumbnailImageSrcMap) {
numInstances: ds.numImageFrames,
countIcon: ds.countIcon,
StudyInstanceUID: ds.StudyInstanceUID,
messages: ds.messages,
componentType,
imageSrc,
dragData: {
Expand Down
50 changes: 50 additions & 0 deletions extensions/default/src/getDisplaySetMessages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import sortInstancesByPosition from '@ohif/core/src/utils/sortInstancesByPosition';
import { constructableModalities } from '@ohif/core/src/utils/isDisplaySetReconstructable';
import { DisplaySetMessage, DisplaySetMessageList } from '@ohif/core';
import checkMultiFrame from './utils/validations/checkMultiframe';
import checkSingleFrames from './utils/validations/checkSingleFrames';
/**
* Checks if a series is reconstructable to a 3D volume.
*
* @param {Object[]} instances An array of `OHIFInstanceMetadata` objects.
*/
export default function getDisplaySetMessages(
instances: Array<any>,
isReconstructable: boolean
): DisplaySetMessageList {
const messages = new DisplaySetMessageList();
if (!instances.length) {
messages.addMessage(DisplaySetMessage.CODES.NO_VALID_INSTANCES);
}

const firstInstance = instances[0];
// Due to current requirements, LOCALIZER series doesn't have any messages
if (firstInstance.ImageType.includes('LOCALIZER')) {
return messages;
}

const Modality = firstInstance.Modality;
if (!constructableModalities.includes(Modality)) {
return messages;
}

const isMultiframe = firstInstance.NumberOfFrames > 1;
// Can't reconstruct if all instances don't have the ImagePositionPatient.
if (
!isMultiframe &&
!instances.every(instance => instance.ImagePositionPatient)
) {
messages.addMessage(DisplaySetMessage.CODES.NO_POSITION_INFORMATION);
}

const sortedInstances = sortInstancesByPosition(instances);

isMultiframe
? checkMultiFrame(sortedInstances[0], messages)
: checkSingleFrames(sortedInstances, messages);

if (!isReconstructable) {
messages.addMessage(DisplaySetMessage.CODES.NOT_RECONSTRUCTABLE);
}
return messages;
}
5 changes: 4 additions & 1 deletion extensions/default/src/getSopClassHandlerModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import sopClassDictionary from '@ohif/core/src/utils/sopClassDictionary';
import ImageSet from '@ohif/core/src/classes/ImageSet';
import isDisplaySetReconstructable from '@ohif/core/src/utils/isDisplaySetReconstructable';
import { id } from './id';
import getDisplaySetMessages from './getDisplaySetMessages';

const sopClassHandlerName = 'stack';

Expand All @@ -18,8 +19,9 @@ const makeDisplaySet = instances => {
value: isReconstructable,
averageSpacingBetweenFrames,
} = isDisplaySetReconstructable(instances);

// set appropriate attributes to image set...
const messages = getDisplaySetMessages(instances, isReconstructable);

imageSet.setAttributes({
displaySetInstanceUID: imageSet.uid, // create a local alias for the imageSet UID
SeriesDate: instance.SeriesDate,
Expand All @@ -36,6 +38,7 @@ const makeDisplaySet = instances => {
numImageFrames: instances.length,
SOPClassHandlerId: `${id}.sopClassHandlerModule.${sopClassHandlerName}`,
isReconstructable,
messages,
averageSpacingBetweenFrames: averageSpacingBetweenFrames || null,
});

Expand Down
20 changes: 20 additions & 0 deletions extensions/default/src/utils/calculateScanAxisNormal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { vec3 } from 'gl-matrix';

/**
* Calculates the scanAxisNormal based on a image orientation vector extract from a frame
* @param {*} imageOrientation
* @returns
*/
export default function calculateScanAxisNormal(imageOrientation) {
const rowCosineVec = vec3.fromValues(
imageOrientation[0],
imageOrientation[1],
imageOrientation[2]
);
const colCosineVec = vec3.fromValues(
imageOrientation[3],
imageOrientation[4],
imageOrientation[5]
);
return vec3.cross(vec3.create(), rowCosineVec, colCosineVec);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import toNumber from '@ohif/core/src/utils/toNumber';

/**
* Check if all voxels in series images has same number of components (samplesPerPixel)
* @param {*} instances
* @returns
*/
export default function areAllImageComponentsEqual(
instances: Array<any>
): boolean {
if (!instances?.length) {
return false;
}
const firstImage = instances[0];
const firstImageSamplesPerPixel = toNumber(firstImage.SamplesPerPixel);

for (let i = 1; i < instances.length; i++) {
const instance = instances[i];
const { SamplesPerPixel } = instance;

if (SamplesPerPixel !== firstImageSamplesPerPixel) {
return false;
}
}
return true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import toNumber from '@ohif/core/src/utils/toNumber';

/**
* Check if the frames in a series has different dimensions
* @param {*} instances
* @returns
*/
export default function areAllImageDimensionsEqual(
instances: Array<any>
): boolean {
if (!instances?.length) {
return false;
}
const firstImage = instances[0];
const firstImageRows = toNumber(firstImage.Rows);
const firstImageColumns = toNumber(firstImage.Columns);

for (let i = 1; i < instances.length; i++) {
const instance = instances[i];
const { Rows, Columns } = instance;

if (Rows !== firstImageRows || Columns !== firstImageColumns) {
return false;
}
}
return true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import toNumber from '@ohif/core/src/utils/toNumber';
import { _isSameOrientation } from '@ohif/core/src/utils/isDisplaySetReconstructable';

/**
* Check is the series has frames with different orientations
* @param {*} instances
* @returns
*/
export default function areAllImageOrientationsEqual(
instances: Array<any>
): boolean {
if (!instances?.length) {
return false;
}
const firstImage = instances[0];
const firstImageOrientationPatient = toNumber(
firstImage.ImageOrientationPatient
);

for (let i = 1; i < instances.length; i++) {
const instance = instances[i];
const imageOrientationPatient = toNumber(instance.ImageOrientationPatient);

if (
!_isSameOrientation(imageOrientationPatient, firstImageOrientationPatient)
) {
return false;
}
}
return true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { vec3 } from 'gl-matrix';
import toNumber from '@ohif/core/src/utils/toNumber';
import { _getPerpendicularDistance } from '@ohif/core/src/utils/isDisplaySetReconstructable';
import calculateScanAxisNormal from '../calculateScanAxisNormal';

/**
* Checks if there is a position shift between consecutive frames
* @param {*} previousPosition
* @param {*} actualPosition
* @param {*} scanAxisNormal
* @param {*} averageSpacingBetweenFrames
* @returns
*/
function _checkSeriesPositionShift(
previousPosition,
actualPosition,
scanAxisNormal,
averageSpacingBetweenFrames
) {
// predicted position should be the previous position added by the multiplication
// of the scanAxisNormal and the average spacing between frames
const predictedPosition = vec3.scaleAndAdd(
vec3.create(),
previousPosition,
scanAxisNormal,
averageSpacingBetweenFrames
);
return (
vec3.distance(actualPosition, predictedPosition) >
averageSpacingBetweenFrames
);
}

/**
* Checks if a series has position shifts between consecutive frames
* @param {*} instances
* @returns
*/
export default function areAllImagePositionsEqual(
instances: Array<any>
): boolean {
if (!instances?.length) {
return false;
}
const firstImageOrientationPatient = toNumber(
instances[0].ImageOrientationPatient
);
const scanAxisNormal = calculateScanAxisNormal(firstImageOrientationPatient);
const firstImagePositionPatient = toNumber(instances[0].ImagePositionPatient);
const lastIpp = toNumber(
instances[instances.length - 1].ImagePositionPatient
);

const averageSpacingBetweenFrames =
_getPerpendicularDistance(firstImagePositionPatient, lastIpp) /
(instances.length - 1);

let previousImagePositionPatient = firstImagePositionPatient;
for (let i = 1; i < instances.length; i++) {
const instance = instances[i];
const imagePositionPatient = toNumber(instance.ImagePositionPatient);

if (
_checkSeriesPositionShift(
previousImagePositionPatient,
imagePositionPatient,
scanAxisNormal,
averageSpacingBetweenFrames
)
) {
return false;
}
previousImagePositionPatient = imagePositionPatient;
}
return true;
}
Loading

0 comments on commit b5b0435

Please sign in to comment.