-
Notifications
You must be signed in to change notification settings - Fork 385
fix CircleROI tool for wsi #1940
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b9c9f50
ca3fdb8
3c6e74a
0356835
c6db595
f8b94a0
64a7b95
7f07ac4
bebdbd6
9f286a5
57c88c5
63336f6
5ded038
99f2d2b
048f9dd
00bf564
65d8149
b8fb6b2
73a6d4b
6d21c80
88b5bfd
613279f
5fb2331
1fb803a
474fb89
cd18632
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,6 @@ import type { | |
CPUIImageData, | ||
ViewportInput, | ||
BoundsIJK, | ||
CPUImageData, | ||
} from '../types'; | ||
import uuidv4 from '../utilities/uuidv4'; | ||
import * as metaData from '../metaData'; | ||
|
@@ -228,8 +227,16 @@ class WSIViewport extends Viewport { | |
this.setProperties({}); | ||
} | ||
|
||
protected getScalarData() { | ||
return null; | ||
protected _getScalarData() { | ||
// Return an empty CanvasScalarData object | ||
type CanvasScalarData = Uint8ClampedArray & { | ||
frameNumber?: number; | ||
getRange?: () => [number, number]; | ||
}; | ||
const emptyData = new Uint8ClampedArray() as CanvasScalarData; | ||
emptyData.getRange = () => [0, 255]; | ||
emptyData.frameNumber = -1; | ||
return emptyData; | ||
} | ||
|
||
public getImageData(): CPUIImageData { | ||
|
@@ -244,7 +251,7 @@ class WSIViewport extends Viewport { | |
getDirection: () => metadata.direction, | ||
getDimensions: () => metadata.dimensions, | ||
getRange: () => [0, 255], | ||
getScalarData: () => this.getScalarData(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a viewReference to the getter as an optional? I know we don't pass it in yet, but we need to start thinking about it as the getScalarData for whole slide imaging won't be able to return the entire scalar data. |
||
getScalarData: () => this._getScalarData(), | ||
getSpacing: () => metadata.spacing, | ||
worldToIndex: (point: Point3) => { | ||
const canvasPoint = this.worldToCanvas(point); | ||
|
@@ -272,9 +279,10 @@ class WSIViewport extends Viewport { | |
preScale: { | ||
scaled: false, | ||
}, | ||
scalarData: this.getScalarData(), | ||
scalarData: this._getScalarData(), | ||
imageData, | ||
// It is for the annotations to work, since all of them work on voxelManager and not on scalarData now | ||
/* | ||
voxelManager: { | ||
forEach: ( | ||
callback: (args: { | ||
|
@@ -298,6 +306,7 @@ class WSIViewport extends Viewport { | |
}); | ||
}, | ||
}, | ||
*/ | ||
}; | ||
|
||
// @ts-expect-error we need to fully migrate the voxelManager to the new system | ||
|
@@ -612,15 +621,20 @@ class WSIViewport extends Viewport { | |
|
||
public getRotation = () => 0; | ||
|
||
protected canvasToIndex = (canvasPos: Point2): Point2 => { | ||
protected canvasToIndex = (canvasPos: Point2): Point3 => { | ||
const transform = this.getTransform(); | ||
transform.invert(); | ||
return transform.transformPoint(canvasPos); | ||
const indexPoint = transform.transformPoint( | ||
canvasPos.map((it) => it * devicePixelRatio) as Point2 | ||
); | ||
return [indexPoint[0], indexPoint[1], 0] as Point3; | ||
}; | ||
|
||
protected indexToCanvas = (indexPos: Point2): Point2 => { | ||
const transform = this.getTransform(); | ||
return transform.transformPoint(indexPos); | ||
return transform | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will need to convert back to negative values, so if you on initial setup store an index of which values are negative and multiple by that vector you should get the right sign. |
||
.transformPoint([indexPos[0], indexPos[1]]) | ||
.map((it) => it / devicePixelRatio) as Point2; | ||
}; | ||
|
||
/** This can be implemented later when multi-slice WSI is supported */ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -982,19 +982,21 @@ class CircleROITool extends AnnotationTool { | |
pixelUnitsOptions | ||
); | ||
|
||
const pointsInShape = voxelManager.forEach( | ||
this.configuration.statsCalculator.statsCallback, | ||
{ | ||
isInObject: (pointLPS) => | ||
pointInEllipse(ellipseObj, pointLPS, { fast: true }), | ||
boundsIJK, | ||
imageData, | ||
returnPoints: this.configuration.storePointData, | ||
} | ||
); | ||
let pointsInShape; | ||
if (voxelManager) { | ||
pointsInShape = voxelManager.forEach( | ||
this.configuration.statsCalculator.statsCallback, | ||
{ | ||
isInObject: (pointLPS) => | ||
pointInEllipse(ellipseObj, pointLPS, { fast: true }), | ||
boundsIJK, | ||
imageData, | ||
returnPoints: this.configuration.storePointData, | ||
} | ||
); | ||
} | ||
|
||
const stats = this.configuration.statsCalculator.getStatistics(); | ||
|
||
cachedStats[targetId] = { | ||
Modality: metadata.Modality, | ||
area, | ||
|
@@ -1028,6 +1030,14 @@ class CircleROITool extends AnnotationTool { | |
}; | ||
|
||
_isInsideVolume = (index1, index2, dimensions) => { | ||
// for wsiViewport | ||
if (index1[1] < 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you put this fix into the WSIViewport itself? |
||
index1[1] = -index1[1]; | ||
} | ||
if (index2[1] < 0) { | ||
index2[1] = -index2[1]; | ||
Comment on lines
+1033
to
+1038
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't look good. Could you please check if the viewport type is WSI before proceeding? I imagine this might disrupt other types of viewports. |
||
} | ||
|
||
return ( | ||
csUtils.indexWithinDimensions(index1, dimensions) && | ||
csUtils.indexWithinDimensions(index2, dimensions) | ||
|
@@ -1131,15 +1141,15 @@ function defaultGetTextLines(data, targetId): string[] { | |
textLines.push(areaLine); | ||
} | ||
|
||
if (mean) { | ||
if (AnnotationTool.isNumber(mean)) { | ||
textLines.push(`Mean: ${csUtils.roundNumber(mean)} ${modalityUnit}`); | ||
} | ||
|
||
if (max) { | ||
if (AnnotationTool.isNumber(max)) { | ||
textLines.push(`Max: ${csUtils.roundNumber(max)} ${modalityUnit}`); | ||
} | ||
|
||
if (stdDev) { | ||
if (AnnotationTool.isNumber(stdDev)) { | ||
textLines.push(`Std Dev: ${csUtils.roundNumber(stdDev)} ${modalityUnit}`); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -474,8 +474,6 @@ class RectangleROITool extends AnnotationTool { | |
|
||
this.editData.hasMoved = true; | ||
|
||
const enabledElement = getEnabledElement(element); | ||
|
||
triggerAnnotationRenderForViewportIds(viewportIdsToRender); | ||
|
||
if (annotation.invalidated) { | ||
|
@@ -930,16 +928,18 @@ class RectangleROITool extends AnnotationTool { | |
pixelUnitsOptions | ||
); | ||
|
||
const pointsInShape = voxelManager.forEach( | ||
this.configuration.statsCalculator.statsCallback, | ||
{ | ||
boundsIJK, | ||
imageData, | ||
returnPoints: this.configuration.storePointData, | ||
} | ||
); | ||
let pointsInShape; | ||
if (voxelManager) { | ||
pointsInShape = voxelManager.forEach( | ||
this.configuration.statsCalculator.statsCallback, | ||
{ | ||
boundsIJK, | ||
imageData, | ||
returnPoints: this.configuration.storePointData, | ||
} | ||
); | ||
} | ||
const stats = this.configuration.statsCalculator.getStatistics(); | ||
|
||
cachedStats[targetId] = { | ||
Modality: metadata.Modality, | ||
area, | ||
|
@@ -968,6 +968,14 @@ class RectangleROITool extends AnnotationTool { | |
}; | ||
|
||
_isInsideVolume = (index1, index2, dimensions) => { | ||
// for wsiViewport | ||
if (index1[1] < 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't look good. Could you please check if the viewport type is WSI before proceeding? I imagine this might disrupt other types of viewports. |
||
index1[1] = -index1[1]; | ||
} | ||
if (index2[1] < 0) { | ||
index2[1] = -index2[1]; | ||
} | ||
|
||
return ( | ||
csUtils.indexWithinDimensions(index1, dimensions) && | ||
csUtils.indexWithinDimensions(index2, dimensions) | ||
|
@@ -1048,12 +1056,16 @@ function defaultGetTextLines(data, targetId: string): string[] { | |
} | ||
|
||
const textLines: string[] = []; | ||
|
||
textLines.push(`Area: ${csUtils.roundNumber(area)} ${areaUnit}`); | ||
textLines.push(`Mean: ${csUtils.roundNumber(mean)} ${modalityUnit}`); | ||
textLines.push(`Max: ${csUtils.roundNumber(max)} ${modalityUnit}`); | ||
textLines.push(`Std Dev: ${csUtils.roundNumber(stdDev)} ${modalityUnit}`); | ||
|
||
if (AnnotationTool.isNumber(mean)) { | ||
textLines.push(`Mean: ${csUtils.roundNumber(mean)} ${modalityUnit}`); | ||
} | ||
if (AnnotationTool.isNumber(max)) { | ||
textLines.push(`Max: ${csUtils.roundNumber(max)} ${modalityUnit}`); | ||
} | ||
if (AnnotationTool.isNumber(stdDev)) { | ||
textLines.push(`Std Dev: ${csUtils.roundNumber(stdDev)} ${modalityUnit}`); | ||
} | ||
return textLines; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add an emptyData.region that is a rectangle of the enclosing region, and a scale parameter? The region should be zero sized for now, and the scale can be 1, but again I'd like to start thinking about the future.