feat(hp): Add displayArea option for Hanging protocols and example with Mamo(#3808)

This commit is contained in:
Bill Wallace authored and GitHub committed 2024-05-29 11:31:09 -04:00
1 parent cb30b97610
commit 18ac08ed86
28 files changed
+771 -27

No files matched your search

+2 -1
View File
@@ -20,6 +20,7 @@ const PUBLIC_URL = process.env.PUBLIC_URL || '/';
const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js';
const PROXY_TARGET = process.env.PROXY_TARGET;
const PROXY_DOMAIN = process.env.PROXY_DOMAIN;
const OHIF_PORT = Number(process.env.OHIF_PORT || 3000);
const ENTRY_TARGET = process.env.ENTRY_TARGET || `${SRC_DIR}/index.js`;
const Dotenv = require('dotenv-webpack');
const writePluginImportFile = require('./writePluginImportsFile.js');
@@ -143,7 +144,7 @@ module.exports = (env, argv) => {
// http2: true,
// https: true,
open: true,
port: 3000,
port: OHIF_PORT,
client: {
overlay: { errors: true, warnings: false },
},
@@ -0,0 +1,86 @@
import { utilities } from '@cornerstonejs/core';
/**
* Add tests to ensure image consistency and quality
*/
const testPixel = (dx, dy, expectedPixel) => {
cy.get('.cornerstone-canvas').then(v => {
const canvas = v[0];
cy.log(
'testPixel canvas',
dx,
dy,
expectedPixel,
canvas.width,
canvas.height,
canvas.style.width,
canvas.style.height
);
const ctx = canvas.getContext('2d');
cy.window()
.its('cornerstone')
.then(cornerstone => {
const { viewport } = cornerstone.getEnabledElements()[0];
const imageData = viewport.getImageData();
// cy.log("imageData", imageData);
const origin = viewport.worldToCanvas(imageData.origin);
const orX = origin[0] * devicePixelRatio;
const orY = origin[1] * devicePixelRatio;
const x = Math.round(orX + dx);
const y = Math.round(orY + dy);
cy.log('testPixel origin x,y point x,y', orX, orY, x, y);
// cy.log('world origin', imageData.origin);
// cy.log('focal', viewport.getCamera().focalPoint,
// viewport.worldToCanvas(viewport.getCamera().focalPoint));
const pixelData = ctx.getImageData(x, y, 1, 1);
expect(pixelData.data[0]).closeTo(expectedPixel, 1);
});
});
};
describe('CS3D Image Consistency and Quality', () => {
const setupStudySeries = (studyUID, seriesUID) => {
cy.checkStudyRouteInViewer(
studyUID,
`&seriesInstanceUID=${seriesUID}&hangingProtocolId=@ohif/hpScale`
);
cy.initCornerstoneToolsAliases();
cy.initCommonElementsAliases();
};
it('TG18 Resolution Test Displayed 1:1', () => {
setupStudySeries(
'2.16.124.113543.6004.101.103.20021117.061159.1',
'2.16.124.113543.6004.101.103.20021117.061159.1.004'
);
testPixel(1018, 1028, 255);
// Horizontal and vertical delta from this should not be contaminated
// by values from center
testPixel(1019, 1028, 0);
testPixel(1018, 1029, 0);
testPixel(1017, 1028, 0);
testPixel(1018, 1027, 0);
});
// Missing test data - todo
it.skip('8 bit image displayable', () => {
setupStudySeries('1.3.46.670589.17.1.7.1.1.7', '1.3.46.670589.17.1.7.2.1.7');
// Compare with dcm2jpg generated values or by manually computing WL values
testPixel(258, 257, 171);
testPixel(259, 257, 166);
});
it.skip('12 bit image displayable and zoom with pixel spacing', () => {
setupStudySeries(
'1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1',
'1.3.6.1.4.1.25403.345050719074.3824.20170125113608.5'
);
// Compare with dcm2jpg generated values or by manually computing WL values
testPixel(258, 277, 120);
testPixel(259, 277, 122);
});
});
+28
View File
@@ -111,6 +111,34 @@ window.config = {
},
},
},
{
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
sourceName: 'dicomweb2',
configuration: {
friendlyName: 'AWS S3 Static wado secondary server',
name: 'aws',
wadoUriRoot: 'https://d28o5kq0jsoob5.cloudfront.net/dicomweb',
qidoRoot: 'https://d28o5kq0jsoob5.cloudfront.net/dicomweb',
wadoRoot: 'https://d28o5kq0jsoob5.cloudfront.net/dicomweb',
qidoSupportsIncludeField: false,
supportsReject: false,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
enableStudyLazyLoad: true,
supportsFuzzyMatching: false,
supportsWildcard: true,
staticWado: true,
singlepart: 'bulkdata,video',
// whether the data source should use retrieveBulkData to grab metadata,
// and in case of relative path, what would it be relative to, options
// are in the series level or study level (some servers like series some study)
bulkDataURI: {
enabled: true,
relativeResolution: 'studies',
},
omitQuotationForMultipartRequest: true,
},
},
{
friendlyName: 'StaticWado default data',
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
@@ -24,6 +24,18 @@ export type DisplaySetAndViewportOptions = {
displaySetOptions: DisplaySetOptions;
};
export type DisplayArea = {
type?: 'SCALE' | 'FIT';
scale?: number;
interpolationType?: any;
imageArea?: [number, number]; // areaX, areaY
imageCanvasPoint?: {
imagePoint: [number, number]; // imageX, imageY
canvasPoint?: [number, number]; // canvasX, canvasY
};
storeAsInitialCamera?: boolean;
};
export type SetProtocolOptions = {
/** Used to provide a mapping of what keys are provided for which viewport.
* For example, a Chest XRay might use have the display set selector id of
@@ -155,6 +167,7 @@ export type ViewportOptions = {
id?: string;
orientation?: CustomOption<string>;
viewportId?: string;
displayArea?: DisplayArea;
initialImageOptions?: CustomOption<initialImageOptions>;
syncGroups?: CustomOption<SyncGroup>[];
customViewportProps?: Record<string, unknown>;
@@ -293,6 +293,7 @@ alternative data source (or even specify different default hotkeys).
| `APP_CONFIG` | Which [configuration file][config-file] to copy to output as `app-config.js` | `config/default.js` |
| `PROXY_TARGET` | When developing, proxy requests that match this pattern to `PROXY_DOMAIN` | `undefined` |
| `PROXY_DOMAIN` | When developing, proxy requests from `PROXY_TARGET` to `PROXY_DOMAIN` | `undefined` |
| `OHIF_PORT` | The port to run the webpack server on for PWA builds. | `3000` |
You can also create a new config file and specify its path relative to the build
output's root by setting the `APP_CONFIG` environment variable. You can set the
@@ -281,21 +281,22 @@ A list of criteria for the protocol along with the provided points for ranking.
},
```
### `from` attribute
The from attribute allows getting the attribute to test from some other object
such as the prior study, the list of studies overall or another module provided
value. Some of the possible attributes are:
### `from` attribute (optional)
The `from` attribute allows you to retrieve the attribute to test from another object, such as the previous study, the overall list of studies, or another provided value from a module.
* `prior`: To get the value from the prior study.
* `activeStudy`: To match the active study
* `studies`: To match the list of studies to display
* `displaySets`: The display sets for the current study
* `allDisplaySets`: Alll available display sets
* `instance`: An instance from the current display set being tested
* `options`: Gets the options object itself, eg if you want a simple top level
value.
The values provided by OHIF which you can use are:
### displaySetSelectors
- `activeStudy`: to use the metadata of the active study to match
- `studies`: to use the metadata of the list of studies (all studies) to match
- `allDisplaySets`: all available display sets
- `displaySets`: if the selector has matched a study, these are the display sets for that study
- `prior`: the metadata of the first study in the list of studies that is not the active study
- `options`: during matching, we also provide an options object with the following information that you can use as the `from` value:
- `studyInstanceUIDsIndex`: the index of the study in the list of studies
- `instance`: the metadata of the instance being matched, which is exactly the displaySet.instance metadata.
### displaySetSelectors (mandatory)
Defines the display sets that the protocol will use for arrangement.
```js
+1 -1
View File
@@ -60,7 +60,7 @@
"react-window": "^1.8.9",
"react-with-direction": "^1.3.1",
"swiper": "^8.4.2",
"webpack": "^5.81.0"
"webpack": "^5.89.0"
},
"devDependencies": {
"@babel/core": "^7.23.2",