Skip to content

Commit 69125ce

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

File tree

1 file changed

+169
-170
lines changed

1 file changed

+169
-170
lines changed

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

Lines changed: 169 additions & 170 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,181 +16,173 @@ 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)=>{
37-
const { HangingProtocolService } = this.serviceManager.services
38-
if(HangingProtocolService.protocol.id === 'breast') this.handleBreastDensityHP(evt)
39-
})
35+
init() {
36+
CornerstoneEventTarget.addEventListener(
37+
CS_EVENTS.STACK_VIEWPORT_NEW_STACK,
38+
(evt) => {
39+
const { HangingProtocolService } = this.serviceManager.services;
40+
if (HangingProtocolService.protocol.id === 'breast')
41+
this.handleBreastDensityHP(evt);
42+
}
43+
);
44+
}
45+
46+
private handleBreastDensityHP(evt) {
47+
const { HangingProtocolService, cornerstoneViewportService } =
48+
this.serviceManager.services;
49+
const { element, viewportId } = evt.detail;
50+
const enabledElement = getEnabledElement(element);
51+
const viewport = enabledElement?.viewport;
52+
if (!viewport) return;
53+
54+
const { voiRange, invert } = (viewport as IStackViewport).getProperties();
55+
const cutoff = invert ? voiRange?.upper : voiRange?.lower;
56+
if (cutoff === undefined || cutoff === null) {
57+
return;
4058
}
4159

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-
}
60+
const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
61+
const matchedDisplaySets = Array.from(
62+
HangingProtocolService.displaySetMatchDetails.values()
63+
);
64+
const matchedDisplaySetIndex = matchedDisplaySets.findIndex(
65+
(displayset) =>
66+
displayset.displaySetInstanceUID ===
67+
viewportInfo.viewportData.data.displaySetInstanceUID
68+
);
6169

62-
const viewportInfo =
63-
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-
);
70+
const matchedDisplaySetKeys = Array.from(
71+
HangingProtocolService.displaySetMatchDetails.keys()
72+
);
73+
const matchedDisplaySet = matchedDisplaySetKeys[matchedDisplaySetIndex];
74+
if (!matchedDisplaySet) return;
75+
76+
const imageData = viewport.getImageData();
77+
const scalarData = imageData?.scalarData;
78+
const dimensions = imageData?.dimensions;
79+
if (!scalarData || !dimensions) return;
80+
81+
// probably will need to account for
82+
// imageData.direction
83+
// interesting that dim[1], dim[0] are reversed for vtk.js => tf.js
84+
// assume this direction does not change
85+
const { bboxWidth, bboxHeight, width, height } = tf.tidy(() => {
86+
const tensor = tf.tensor2d(new Float32Array(scalarData), [
87+
dimensions[1],
88+
dimensions[0],
89+
]);
90+
const mask = tensor.greater(cutoff); // get boolean
91+
const widthBool = mask.any(0); // height?
92+
const heightBool = mask.any(1); // width?
93+
94+
// get bbox
95+
const left = widthBool.argMax();
96+
const right = widthBool.reverse().argMax().mul(-1).add(widthBool.size);
97+
const top = heightBool.argMax();
98+
const bottom = heightBool.reverse().argMax().mul(-1).add(heightBool.size);
99+
100+
// get percentage difference in width and height
101+
const bboxWidth = right.sub(left).dataSync()[0];
102+
const bboxHeight = bottom.sub(top).dataSync()[0];
103+
const width = widthBool.size;
104+
const height = heightBool.size;
105+
106+
return {
107+
bboxWidth,
108+
bboxHeight,
109+
width,
110+
height,
111+
};
112+
});
72113

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
102-
.reverse()
103-
.argMax()
104-
.mul(-1)
105-
.add(heightBool.size);
106-
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,
114+
const bboxAspectRatio = bboxWidth / bboxHeight;
115+
const canvasAspectRatio = viewport.sWidth / viewport.sHeight;
116+
// console.log({bboxAspectRatio, canvasAspectRatio})
117+
// if(bboxAspectRatio > canvasAspectRatio){
118+
// bboxWidth = canvasAspectRatio*bboxHeight
119+
// bboxAspectRatio = bboxWidth/bboxHeight
120+
// console.log('changed', {bboxAspectRatio, canvasAspectRatio})
121+
// }
122+
123+
const bboxWidthPercentage = bboxWidth / width; // add buffer
124+
const bboxHeightPercentage = bboxHeight / height;
125+
126+
// TODO do not hard code, pick the max between bboxwidth and aspect ratio height
127+
const areaZoom = bboxWidthPercentage;
128+
//const panAmount = (1 - areaZoom) / 2;
129+
130+
if (matchedDisplaySet === 'LMLO') {
131+
viewport.setDisplayArea(
132+
{
133+
imageArea: [areaZoom, areaZoom],
134+
imageCanvasPoint: {
135+
canvasPoint: [0, 0.5],
136+
imagePoint: [0, 0.5],
146137
},
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,
138+
storeAsInitialCamera: true,
139+
},
140+
true
141+
);
142+
}
143+
if (matchedDisplaySet === 'RMLO') {
144+
viewport.setDisplayArea(
145+
{
146+
imageArea: [areaZoom, areaZoom],
147+
imageCanvasPoint: {
148+
canvasPoint: [1, 0.5],
149+
imagePoint: [1, 0.5],
159150
},
151+
storeAsInitialCamera: true,
152+
},
160153

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,
154+
true
155+
);
156+
}
157+
if (matchedDisplaySet === 'LCC') {
158+
viewport.setDisplayArea(
159+
{
160+
imageArea: [areaZoom, areaZoom],
161+
imageCanvasPoint: {
162+
canvasPoint: [0, 0.5],
163+
imagePoint: [0, 0.5],
173164
},
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,
165+
storeAsInitialCamera: true,
166+
},
167+
true
168+
);
169+
}
170+
if (matchedDisplaySet === 'RCC') {
171+
viewport.setDisplayArea(
172+
{
173+
imageArea: [areaZoom, areaZoom],
174+
imageCanvasPoint: {
175+
canvasPoint: [1, 0.5],
176+
imagePoint: [1, 0.5],
186177
},
187-
true
188-
);
189-
}
178+
storeAsInitialCamera: true,
179+
},
180+
true
181+
);
190182
}
183+
}
191184

192-
destroy() {
193-
}
185+
destroy() {}
194186

195187
public async focusToSegment(segmentationId, segmentIndex) {
196188
const {
@@ -201,7 +193,9 @@ export default class CropDisplayAreaService {
201193
} = this.serviceManager.services;
202194

203195
const segmentation = segmentationService.getSegmentation(segmentationId);
204-
const segDisplayset = displaySetService.getDisplaySetByUID(segmentation.displaySetInstanceUID);
196+
const segDisplayset = displaySetService.getDisplaySetByUID(
197+
segmentation.displaySetInstanceUID
198+
);
205199
if (segDisplayset.Modality !== 'SEG') {
206200
return;
207201
}
@@ -271,11 +265,16 @@ export default class CropDisplayAreaService {
271265
return { xMax, yMax, xMin, yMin };
272266
});
273267

274-
const referencedDisplaySetInstanceUID = segDisplayset.referencedDisplaySetInstanceUID;
268+
const referencedDisplaySetInstanceUID =
269+
segDisplayset.referencedDisplaySetInstanceUID;
275270
const { viewports, activeViewportId } = viewportGridService.getState();
276271
const viewportsWithSegmentation: IStackViewport | IVolumeViewport = [];
277272
viewports.forEach((viewport) => {
278-
if (viewport.displaySetInstanceUIDs.includes(referencedDisplaySetInstanceUID)) {
273+
if (
274+
viewport.displaySetInstanceUIDs.includes(
275+
referencedDisplaySetInstanceUID
276+
)
277+
) {
279278
viewportsWithSegmentation.push(
280279
cornerstoneViewportService.getCornerstoneViewport(viewport.viewportId)
281280
);
@@ -402,4 +401,4 @@ const correctZoomFactors = (
402401

403402
zoomFactors.x /= zoomOutPercentatage / 100;
404403
zoomFactors.y /= zoomOutPercentatage / 100;
405-
};
404+
};

0 commit comments

Comments
 (0)