Skip to content

Commit fcaf0da

Browse files
committed
Corrected cutoff calculation to allow 0 as well.
1 parent df8f5d1 commit fcaf0da

File tree

1 file changed

+151
-157
lines changed

1 file changed

+151
-157
lines changed

extensions/ohif-gradienthealth-extension/src/services/CropDisplayAreaService/CropDisplayAreaService.ts

Lines changed: 151 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { pubSubServiceInterface } from '@ohif/core';
2-
import {
3-
EVENTS as CS_EVENTS,
4-
eventTarget as CornerstoneEventTarget,
5-
getEnabledElement,
6-
cache,
7-
Enums as CSCORE_ENUMS
2+
import {
3+
EVENTS as CS_EVENTS,
4+
eventTarget as CornerstoneEventTarget,
5+
getEnabledElement,
6+
cache,
7+
Enums as CSCORE_ENUMS
88
} from '@cornerstonejs/core';
99
import { Enums as CSTOOLS_ENUMS } from '@cornerstonejs/tools';
1010

@@ -16,180 +16,174 @@ import {
1616
import { getSegDisplaysetsOfReferencedImagesIds } from '../utils';
1717

1818
const EVENTS = {
19-
CROP_DISPLAY_AREA_INIT: 'event::gradienthealth::CropDisplayAreaService:init',
19+
CROP_DISPLAY_AREA_INIT: 'event::gradienthealth::CropDisplayAreaService:init',
2020
};
2121

2222
export default class CropDisplayAreaService {
23-
private serviceManager;
24-
private listeners;
25-
public EVENTS;
26-
27-
constructor(serviceManager) {
28-
this.serviceManager = serviceManager;
29-
this.listeners = {};
30-
this.EVENTS = EVENTS;
31-
window.tf = tf;
32-
Object.assign(this, pubSubServiceInterface);
33-
}
23+
private serviceManager;
24+
private listeners;
25+
public EVENTS;
26+
27+
constructor(serviceManager) {
28+
this.serviceManager = serviceManager;
29+
this.listeners = {};
30+
this.EVENTS = EVENTS;
31+
window.tf = tf;
32+
Object.assign(this, pubSubServiceInterface);
33+
}
3434

35-
init(){
36-
CornerstoneEventTarget.addEventListener(CS_EVENTS.STACK_VIEWPORT_NEW_STACK, (evt)=>{
35+
init(){
36+
CornerstoneEventTarget.addEventListener(CS_EVENTS.STACK_VIEWPORT_NEW_STACK, (evt)=>{
3737
const { HangingProtocolService } = this.serviceManager.services
3838
if(HangingProtocolService.protocol.id === 'breast') this.handleBreastDensityHP(evt)
3939
})
40-
}
40+
}
4141

42-
private handleBreastDensityHP(evt){
43-
const { HangingProtocolService, cornerstoneViewportService } =
44-
this.serviceManager.services;
45-
const { element, viewportId } = evt.detail;
46-
const enabledElement = getEnabledElement(element);
47-
const viewport = enabledElement?.viewport;
48-
if (!viewport) return;
49-
50-
const { voiRange, invert } = (viewport as IStackViewport).getProperties();
51-
let cutoff;
52-
if (voiRange?.lower && !invert) {
53-
cutoff = voiRange?.lower;
54-
}
55-
if (voiRange?.upper && invert) {
56-
cutoff = voiRange?.upper;
57-
}
58-
if (!cutoff) {
59-
return;
60-
}
42+
private handleBreastDensityHP(evt){
43+
const { HangingProtocolService, cornerstoneViewportService } =
44+
this.serviceManager.services;
45+
const { element, viewportId } = evt.detail;
46+
const enabledElement = getEnabledElement(element);
47+
const viewport = enabledElement?.viewport;
48+
if (!viewport) return;
49+
50+
const { voiRange, invert } = (viewport as IStackViewport).getProperties();
51+
const cutoff = invert ? voiRange?.upper : voiRange?.lower;
52+
if (cutoff === undefined || cutoff === null) {
53+
return;
54+
}
6155

62-
const viewportInfo =
56+
const viewportInfo =
6357
cornerstoneViewportService.getViewportInfo(viewportId);
64-
const matchedDisplaySets = Array.from(
65-
HangingProtocolService.displaySetMatchDetails.values()
66-
);
67-
const matchedDisplaySetIndex = matchedDisplaySets.findIndex(
68-
(displayset) =>
69-
displayset.displaySetInstanceUID ===
70-
viewportInfo.viewportData.data.displaySetInstanceUID
71-
);
58+
const matchedDisplaySets = Array.from(
59+
HangingProtocolService.displaySetMatchDetails.values()
60+
);
61+
const matchedDisplaySetIndex = matchedDisplaySets.findIndex(
62+
(displayset) =>
63+
displayset.displaySetInstanceUID ===
64+
viewportInfo.viewportData.data.displaySetInstanceUID
65+
);
7266

73-
const matchedDisplaySetKeys = Array.from(
74-
HangingProtocolService.displaySetMatchDetails.keys()
75-
);
76-
const matchedDisplaySet = matchedDisplaySetKeys[matchedDisplaySetIndex];
77-
if (!matchedDisplaySet) return;
78-
79-
const imageData = viewport.getImageData();
80-
const scalarData = imageData?.scalarData;
81-
const dimensions = imageData?.dimensions;
82-
if (!scalarData || !dimensions) return;
83-
84-
// probably will need to account for
85-
// imageData.direction
86-
// interesting that dim[1], dim[0] are reversed for vtk.js => tf.js
87-
// assume this direction does not change
88-
const { bboxWidth, bboxHeight, width, height } = tf.tidy(() => {
89-
const tensor = tf.tensor2d(new Float32Array(scalarData), [
90-
dimensions[1],
91-
dimensions[0],
92-
]);
93-
const mask = tensor.greater(cutoff); // get boolean
94-
const widthBool = mask.any(0); // height?
95-
const heightBool = mask.any(1); // width?
96-
97-
// get bbox
98-
const left = widthBool.argMax();
99-
const right = widthBool.reverse().argMax().mul(-1).add(widthBool.size);
100-
const top = heightBool.argMax();
101-
const bottom = heightBool
67+
const matchedDisplaySetKeys = Array.from(
68+
HangingProtocolService.displaySetMatchDetails.keys()
69+
);
70+
const matchedDisplaySet = matchedDisplaySetKeys[matchedDisplaySetIndex];
71+
if (!matchedDisplaySet) return;
72+
73+
const imageData = viewport.getImageData();
74+
const scalarData = imageData?.scalarData;
75+
const dimensions = imageData?.dimensions;
76+
if (!scalarData || !dimensions) return;
77+
78+
// probably will need to account for
79+
// imageData.direction
80+
// interesting that dim[1], dim[0] are reversed for vtk.js => tf.js
81+
// assume this direction does not change
82+
const { bboxWidth, bboxHeight, width, height } = tf.tidy(() => {
83+
const tensor = tf.tensor2d(new Float32Array(scalarData), [
84+
dimensions[1],
85+
dimensions[0],
86+
]);
87+
const mask = tensor.greater(cutoff); // get boolean
88+
const widthBool = mask.any(0); // height?
89+
const heightBool = mask.any(1); // width?
90+
91+
// get bbox
92+
const left = widthBool.argMax();
93+
const right = widthBool.reverse().argMax().mul(-1).add(widthBool.size);
94+
const top = heightBool.argMax();
95+
const bottom = heightBool
10296
.reverse()
10397
.argMax()
10498
.mul(-1)
10599
.add(heightBool.size);
106100

107-
// get percentage difference in width and height
108-
const bboxWidth = right.sub(left).dataSync()[0];
109-
const bboxHeight = bottom.sub(top).dataSync()[0];
110-
const width = widthBool.size;
111-
const height = heightBool.size;
112-
113-
return {
114-
bboxWidth,
115-
bboxHeight,
116-
width,
117-
height,
118-
};
119-
});
120-
121-
const bboxAspectRatio = bboxWidth / bboxHeight;
122-
const canvasAspectRatio = viewport.sWidth / viewport.sHeight;
123-
// console.log({bboxAspectRatio, canvasAspectRatio})
124-
// if(bboxAspectRatio > canvasAspectRatio){
125-
// bboxWidth = canvasAspectRatio*bboxHeight
126-
// bboxAspectRatio = bboxWidth/bboxHeight
127-
// console.log('changed', {bboxAspectRatio, canvasAspectRatio})
128-
// }
129-
130-
const bboxWidthPercentage = bboxWidth / width; // add buffer
131-
const bboxHeightPercentage = bboxHeight / height;
132-
133-
// TODO do not hard code, pick the max between bboxwidth and aspect ratio height
134-
const areaZoom = bboxWidthPercentage;
135-
//const panAmount = (1 - areaZoom) / 2;
136-
137-
if (matchedDisplaySet === 'LMLO') {
138-
viewport.setDisplayArea(
139-
{
140-
imageArea: [areaZoom, areaZoom],
141-
imageCanvasPoint: {
142-
canvasPoint: [0, 0.5],
143-
imagePoint: [0, 0.5],
144-
},
145-
storeAsInitialCamera: true,
101+
// get percentage difference in width and height
102+
const bboxWidth = right.sub(left).dataSync()[0];
103+
const bboxHeight = bottom.sub(top).dataSync()[0];
104+
const width = widthBool.size;
105+
const height = heightBool.size;
106+
107+
return {
108+
bboxWidth,
109+
bboxHeight,
110+
width,
111+
height,
112+
};
113+
});
114+
115+
const bboxAspectRatio = bboxWidth / bboxHeight;
116+
const canvasAspectRatio = viewport.sWidth / viewport.sHeight;
117+
// console.log({bboxAspectRatio, canvasAspectRatio})
118+
// if(bboxAspectRatio > canvasAspectRatio){
119+
// bboxWidth = canvasAspectRatio*bboxHeight
120+
// bboxAspectRatio = bboxWidth/bboxHeight
121+
// console.log('changed', {bboxAspectRatio, canvasAspectRatio})
122+
// }
123+
124+
const bboxWidthPercentage = bboxWidth / width; // add buffer
125+
const bboxHeightPercentage = bboxHeight / height;
126+
127+
// TODO do not hard code, pick the max between bboxwidth and aspect ratio height
128+
const areaZoom = bboxWidthPercentage;
129+
//const panAmount = (1 - areaZoom) / 2;
130+
131+
if (matchedDisplaySet === 'LMLO') {
132+
viewport.setDisplayArea(
133+
{
134+
imageArea: [areaZoom, areaZoom],
135+
imageCanvasPoint: {
136+
canvasPoint: [0, 0.5],
137+
imagePoint: [0, 0.5],
146138
},
147-
true
148-
);
149-
}
150-
if (matchedDisplaySet === 'RMLO') {
151-
viewport.setDisplayArea(
152-
{
153-
imageArea: [areaZoom, areaZoom],
154-
imageCanvasPoint: {
155-
canvasPoint: [1, 0.5],
156-
imagePoint: [1, 0.5],
157-
},
158-
storeAsInitialCamera: true,
139+
storeAsInitialCamera: true,
140+
},
141+
true
142+
);
143+
}
144+
if (matchedDisplaySet === 'RMLO') {
145+
viewport.setDisplayArea(
146+
{
147+
imageArea: [areaZoom, areaZoom],
148+
imageCanvasPoint: {
149+
canvasPoint: [1, 0.5],
150+
imagePoint: [1, 0.5],
159151
},
152+
storeAsInitialCamera: true,
153+
},
160154

161-
true
162-
);
163-
}
164-
if (matchedDisplaySet === 'LCC') {
165-
viewport.setDisplayArea(
166-
{
167-
imageArea: [areaZoom, areaZoom],
168-
imageCanvasPoint: {
169-
canvasPoint: [0, 0.5],
170-
imagePoint: [0, 0.5],
171-
},
172-
storeAsInitialCamera: true,
155+
true
156+
);
157+
}
158+
if (matchedDisplaySet === 'LCC') {
159+
viewport.setDisplayArea(
160+
{
161+
imageArea: [areaZoom, areaZoom],
162+
imageCanvasPoint: {
163+
canvasPoint: [0, 0.5],
164+
imagePoint: [0, 0.5],
173165
},
174-
true
175-
);
176-
}
177-
if (matchedDisplaySet === 'RCC') {
178-
viewport.setDisplayArea(
179-
{
180-
imageArea: [areaZoom, areaZoom],
181-
imageCanvasPoint: {
182-
canvasPoint: [1, 0.5],
183-
imagePoint: [1, 0.5],
184-
},
185-
storeAsInitialCamera: true,
166+
storeAsInitialCamera: true,
167+
},
168+
true
169+
);
170+
}
171+
if (matchedDisplaySet === 'RCC') {
172+
viewport.setDisplayArea(
173+
{
174+
imageArea: [areaZoom, areaZoom],
175+
imageCanvasPoint: {
176+
canvasPoint: [1, 0.5],
177+
imagePoint: [1, 0.5],
186178
},
187-
true
188-
);
189-
}
179+
storeAsInitialCamera: true,
180+
},
181+
true
182+
);
190183
}
184+
}
191185

192-
destroy() {
186+
destroy() {
193187
}
194188

195189
public async focusToSegment(segmentationId, segmentIndex) {

0 commit comments

Comments
 (0)