分割标记渲染结构变更
parent
5a7fa1fb77
commit
312ab754e1
|
|
@ -16,6 +16,7 @@
|
|||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.726.1",
|
||||
"@cornerstonejs/adapters": "^4.19.2",
|
||||
"@cornerstonejs/polymorphic-segmentation": "4.19.2",
|
||||
"@cornerstonejs/calculate-suv": "^1.1.0",
|
||||
"@cornerstonejs/core": "^4.19.2",
|
||||
"@cornerstonejs/dicom-image-loader": "^4.19.2",
|
||||
|
|
@ -124,4 +125,4 @@
|
|||
"not dead",
|
||||
"not op_mini all"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -81,6 +81,19 @@ import {
|
|||
} from './helpers/index.js'
|
||||
import { vec3, mat4 } from 'gl-matrix'
|
||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||
import {
|
||||
renderSegmentation,
|
||||
readingSegmentByConfig,
|
||||
selectSegmentation,
|
||||
selectSegment,
|
||||
createSegmentationRepresentation,
|
||||
viewSegmentation,
|
||||
viewSegment,
|
||||
jumpBidirectional,
|
||||
viewBidirectional,
|
||||
changeColor,
|
||||
resetViewport
|
||||
} from "./helpers/segmentations"
|
||||
export default {
|
||||
name: 'MPRViewport',
|
||||
props: {
|
||||
|
|
@ -105,6 +118,32 @@ export default {
|
|||
histogramVisible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
actionConfiguration: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
SegmentConfig: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
curSegSeries: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
segmentIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
segmentationId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
@ -155,6 +194,39 @@ export default {
|
|||
this.$nextTick(() => {
|
||||
this.initViewport()
|
||||
})
|
||||
DicomEvent.$on('createSegmentationRepresentation', (segmentationId) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
createSegmentationRepresentation(this.viewportId, segmentationId)
|
||||
})
|
||||
DicomEvent.$on('viewSegmentation', (obj) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
viewSegmentation(obj, this.viewportId)
|
||||
})
|
||||
DicomEvent.$on('viewSegment', (obj) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
viewSegment(obj, this.viewportId)
|
||||
})
|
||||
DicomEvent.$on('jumpBidirectional', (obj) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
jumpBidirectional(obj, this.viewportId, this.volumeId)
|
||||
})
|
||||
DicomEvent.$on('viewBidirectional', (obj) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
viewBidirectional(obj, this.viewportId)
|
||||
})
|
||||
DicomEvent.$on('changeColor', (obj) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
changeColor(obj, this.viewportId)
|
||||
})
|
||||
DicomEvent.$on('resetViewport', () => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
resetViewport(this.viewportId)
|
||||
})
|
||||
DicomEvent.$on('renderSegmentation', async (viewportId) => {
|
||||
// if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
if (this.viewportId !== viewportId) return false
|
||||
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.segmentationId, this.segmentIndex, this.renderingEngineId, null, this.actionConfiguration)
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
MPRInfo: {
|
||||
|
|
@ -173,6 +245,25 @@ export default {
|
|||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
SegmentConfig: {
|
||||
handler() {
|
||||
if (!this.segmentationId) return false
|
||||
if (!this.series.TaskInfo) return false
|
||||
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
segmentIndex() {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
if (this.segmentIndex <= 0) return false
|
||||
selectSegment(this.viewportId, this.segmentationId, this.segmentIndex)
|
||||
},
|
||||
segmentationId() {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
if (!this.segmentationId) return false
|
||||
selectSegmentation(this.viewportId, this.segmentationId)
|
||||
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -505,7 +596,6 @@ export default {
|
|||
setCtTransferFunctionForVolumeActor(r)
|
||||
}
|
||||
console.log("渲染成功")
|
||||
DicomEvent.$emit("isloaded", { isChange: false })
|
||||
}
|
||||
}]).then(r => {
|
||||
if (data.isLocation || !this.imageInfo.zoom) {
|
||||
|
|
@ -522,6 +612,7 @@ export default {
|
|||
renderingEngine.render()
|
||||
}, 100)
|
||||
}
|
||||
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.segmentationId, this.segmentIndex, this.renderingEngineId, null, this.actionConfiguration)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,7 +313,9 @@
|
|||
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
|
||||
<VolumeViewport :ref="`viewport-${index}`" :data-viewport-uid="`viewport-${index}`"
|
||||
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-${index}`" :viewport-index="index"
|
||||
:histogramVisible="histogramVisible" @activeViewport="activeViewport"
|
||||
:histogramVisible="histogramVisible" :actionConfiguration="actionConfiguration"
|
||||
:SegmentConfig="SegmentConfig" :segmentationId.sync="segId" :segmentIndex.sync="segIndex"
|
||||
:curSegSeries.sync="curSegSeries" @activeViewport="activeViewport"
|
||||
@toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
|
||||
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup"
|
||||
@resetViewport="resetViewport" v-if="readingTool === 3"
|
||||
|
|
@ -333,7 +335,10 @@
|
|||
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
|
||||
<MPRViewport :ref="`viewport-MPR-${index}`" :data-viewport-uid="`viewport-MPR-${index}`"
|
||||
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-MPR-${index}`"
|
||||
:viewport-index="index" :MPRInfo="MPRInfo" @activeViewport="activeViewport" @setMPRInfo="setMPRInfo"
|
||||
:viewport-index="index" :histogramVisible="histogramVisible"
|
||||
:actionConfiguration="actionConfiguration" :SegmentConfig="SegmentConfig"
|
||||
:segmentationId.sync="segId" :segmentIndex.sync="segIndex" :curSegSeries.sync="curSegSeries"
|
||||
:MPRInfo="MPRInfo" @activeViewport="activeViewport" @setMPRInfo="setMPRInfo"
|
||||
@toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
|
||||
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup"
|
||||
v-resize="(e) => handleSizeChange(e, `viewport-MPR-${index}`)" />
|
||||
|
|
@ -362,9 +367,11 @@
|
|||
<Segmentations ref="Segmentations" :visitInfo="taskInfo" :isMPR="isMPR"
|
||||
:volumeToolGroupId="volumeToolGroupId" :viewportKey="viewportKey" :global-loading.sync="loading"
|
||||
:loadingText.sync="loadingText" :rendering-engine-id="renderingEngineId"
|
||||
:activeViewportIndex="activeViewportIndex" :activeTool.sync="activeTool"
|
||||
:actionConfiguration="actionConfiguration" :histogramVisible="histogramVisible"
|
||||
@setToolsPassive="setToolsPassive" @resetQuestion="resetQuestion" />
|
||||
:SegmentConfig="SegmentConfig" :segId.sync="segId" :segIndex.sync="segIndex"
|
||||
:curSegSeries.sync="curSegSeries" :activeViewportIndex="activeViewportIndex"
|
||||
:activeTool.sync="activeTool" :actionConfiguration="actionConfiguration"
|
||||
:histogramVisible="histogramVisible" @setToolsPassive="setToolsPassive"
|
||||
@resetQuestion="resetQuestion" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('trials:reading:dicom3D:tabs:ecrf')" name="ecrf">
|
||||
<div v-for="s in visitTaskList" v-show="lastViewportTaskId === s.VisitTaskId" :key="s.VisitTaskId"
|
||||
|
|
@ -498,6 +505,11 @@
|
|||
<!--直方图-->
|
||||
<histogram ref="histogram" v-if="readingTool === 3" :visible.sync="histogramVisible" :activeTool.sync="activeTool"
|
||||
:viewportKey="viewportKey" :rendering-engine-id="renderingEngineId" :activeViewportIndex="activeViewportIndex" />
|
||||
<!--分割可视化窗口-->
|
||||
<!-- <SurfaceViewport ref="surfaceViewport" viewportId="surfaceViewport" v-if="readingTool === 3"
|
||||
:visible.sync="surfaceVisible" :renderingEngineId="renderingEngineId" :visitInfo="taskInfo" />
|
||||
<ContourViewport ref="contourViewport" viewportId="contourViewport" v-if="readingTool === 3"
|
||||
:renderingEngineId="renderingEngineId" :visitInfo="taskInfo" /> -->
|
||||
<upload-dicom-and-nonedicom v-if="uploadImageVisible" :subject-id="uploadSubjectId"
|
||||
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible"
|
||||
:visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" />
|
||||
|
|
@ -516,6 +528,7 @@ import {
|
|||
RenderingEngine,
|
||||
Enums,
|
||||
// imageLoader,
|
||||
// CONSTANTS,
|
||||
metaData,
|
||||
volumeLoader,
|
||||
getRenderingEngine,
|
||||
|
|
@ -537,6 +550,8 @@ import MPRViewport from './MPRViewport'
|
|||
import VolumeViewport from './VolumeViewport'
|
||||
import Segmentations from './Segmentations'
|
||||
import histogram from "./histogram"
|
||||
// import SurfaceViewport from "./SurfaceViewport"
|
||||
// import ContourViewport from "./ContourViewport"
|
||||
import mRecisit from './mRecist/QuestionList'
|
||||
import recisit from './Recist/QuestionList'
|
||||
import customizeQuestionList from './customize/QuestionList'
|
||||
|
|
@ -567,6 +582,9 @@ const {
|
|||
ToolGroupManager,
|
||||
Enums: csToolsEnums,
|
||||
StackScrollTool,
|
||||
TrackballRotateTool,
|
||||
PlanarFreehandContourSegmentationTool,
|
||||
SplineContourSegmentationTool,
|
||||
// ScaleOverlayTool,
|
||||
PanTool,
|
||||
ZoomTool,
|
||||
|
|
@ -629,6 +647,8 @@ export default {
|
|||
VolumeViewport,
|
||||
Segmentations,
|
||||
histogram,
|
||||
// SurfaceViewport,
|
||||
// ContourViewport,
|
||||
mRecisit,
|
||||
recisit,
|
||||
customizeQuestionList,
|
||||
|
|
@ -662,7 +682,7 @@ export default {
|
|||
activeTaskIndex: -1,
|
||||
activeStudyIndex: -1,
|
||||
activeSeriesIndex: -1,
|
||||
currentVisitInfo: null,
|
||||
currentVisitInfo: {},
|
||||
layout: 1,
|
||||
cellsMax: 4,
|
||||
rows: 1,
|
||||
|
|
@ -772,14 +792,28 @@ export default {
|
|||
},
|
||||
},
|
||||
},
|
||||
SegmentConfig: {
|
||||
renderOutline: true,
|
||||
renderFill: true,
|
||||
fillAlpha: 0.5,
|
||||
outlineWidth: 1,
|
||||
InactiveSegmentations: {
|
||||
show: true,
|
||||
fillAlpha: 0.3,
|
||||
}
|
||||
},
|
||||
segId: null,
|
||||
segIndex: null,
|
||||
curSegSeries: {},
|
||||
fusionOverlayModality: null,
|
||||
lastUpper: null,
|
||||
hasFusionUpperInitialized: false,
|
||||
timer: null,
|
||||
timer: {},
|
||||
FullTimerOut: null,
|
||||
isDelay: false,
|
||||
|
||||
histogramVisible: false
|
||||
histogramVisible: false,
|
||||
// surfaceVisible: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -951,6 +985,11 @@ export default {
|
|||
this.getSystemInfoReading();
|
||||
},
|
||||
methods: {
|
||||
showSurface(obj) {
|
||||
// this.surfaceVisible = true
|
||||
// this.$refs.contourViewport.setSeriesInfo(obj)
|
||||
// this.$refs.surfaceViewport.setSeriesInfo(obj)
|
||||
},
|
||||
async openHistogram() {
|
||||
this.histogramVisible = true
|
||||
this.setToolsPassive()
|
||||
|
|
@ -958,8 +997,8 @@ export default {
|
|||
|
||||
},
|
||||
handleSizeChange(e, viewportId) {
|
||||
// console.log('handleSizeChange', e)
|
||||
this.resetRenderingEngine(viewportId)
|
||||
let index = this.$refs[viewportId][0].series.SliceIndex
|
||||
this.resetRenderingEngine(viewportId, index)
|
||||
},
|
||||
resetQuestion() {
|
||||
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].getQuestions(false)
|
||||
|
|
@ -1297,6 +1336,27 @@ export default {
|
|||
}
|
||||
}
|
||||
]
|
||||
// let element5 = this.$refs.surfaceViewport.$el
|
||||
// let element6 = this.$refs.contourViewport.$el
|
||||
// viewportInputArray.push({
|
||||
// viewportId: 'surfaceViewport',
|
||||
// type: ViewportType.VOLUME_3D,
|
||||
// element: element5,
|
||||
// defaultOptions: {
|
||||
// orientation: Enums.OrientationAxis.CORONAL,
|
||||
// background: [1, 1, 1]
|
||||
// }
|
||||
// })
|
||||
// viewportInputArray.push({
|
||||
// viewportId: 'contourViewport',
|
||||
// type: ViewportType.ORTHOGRAPHIC,
|
||||
// element: element6,
|
||||
// defaultOptions: {
|
||||
// orientation: Enums.OrientationAxis.AXIAL
|
||||
// }
|
||||
// })
|
||||
// viewportIds.push('surfaceViewport')
|
||||
// viewportIds.push('contourViewport')
|
||||
}
|
||||
if ((this.criterionType === 0 && this.readingTool === 0) || this.readingTool === 3) {
|
||||
const volumeElement1 = this.$refs['viewport-MPR-0'][0].$el
|
||||
|
|
@ -1377,6 +1437,7 @@ export default {
|
|||
}
|
||||
renderingEngine.setViewports(viewportInputArray)
|
||||
this.addAnnotationListeners()
|
||||
// cornerstoneTools.addTool(TrackballRotateTool)
|
||||
cornerstoneTools.addTool(StackScrollTool)
|
||||
cornerstoneTools.addTool(PanTool)
|
||||
cornerstoneTools.addTool(ZoomTool)
|
||||
|
|
@ -1401,6 +1462,8 @@ export default {
|
|||
cornerstoneTools.addTool(LabelMapEditWithContourTool)
|
||||
cornerstoneTools.addTool(BrushTool)
|
||||
cornerstoneTools.addTool(SegmentBidirectionalTool)
|
||||
// cornerstoneTools.addTool(PlanarFreehandContourSegmentationTool);
|
||||
// cornerstoneTools.addTool(SplineContourSegmentationTool);
|
||||
viewportIds.forEach((viewportId, i) => {
|
||||
// const toolGroupId = `viewport-${i}`
|
||||
let toolGroupId = viewportId
|
||||
|
|
@ -1410,196 +1473,222 @@ export default {
|
|||
|
||||
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) ? ToolGroupManager.getToolGroup(toolGroupId) : ToolGroupManager.createToolGroup(toolGroupId)
|
||||
toolGroup.addViewport(viewportId, renderingEngineId)
|
||||
toolGroup.addTool(StackScrollTool.toolName, {
|
||||
loop: true, // 启用循环滚动
|
||||
})
|
||||
toolGroup.addTool(ScaleOverlayTool.toolName)
|
||||
|
||||
toolGroup.addTool(PanTool.toolName)
|
||||
toolGroup.addTool(ZoomTool.toolName)
|
||||
toolGroup.addTool(BrushTool.toolName)
|
||||
if (this.readingTool === 3 || toolGroupId === this.volumeToolGroupId) {
|
||||
toolGroup.addToolInstance(
|
||||
'histogram_RectangleROI',
|
||||
RectangleROITool.toolName,
|
||||
);
|
||||
toolGroup.addToolInstance(
|
||||
'histogram_CircleROI',
|
||||
CircleROITool.toolName,
|
||||
);
|
||||
toolGroup.addToolInstance(
|
||||
'histogram_PlanarFreehandROI',
|
||||
PlanarFreehandROITool.toolName,
|
||||
);
|
||||
toolGroup.addToolInstance(
|
||||
'CircularBrush',
|
||||
BrushTool.toolName,
|
||||
{
|
||||
activeStrategy: 'FILL_INSIDE_CIRCLE',
|
||||
preview: {
|
||||
previewColors: {}
|
||||
}
|
||||
}
|
||||
);
|
||||
toolGroup.addToolInstance(
|
||||
'CircularEraser',
|
||||
BrushTool.toolName,
|
||||
{
|
||||
activeStrategy: 'ERASE_INSIDE_CIRCLE',
|
||||
preview: {
|
||||
previewColors: {}
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
toolGroup.addToolInstance(
|
||||
'ThresholdCircle',
|
||||
BrushTool.toolName,
|
||||
{
|
||||
activeStrategy: 'THRESHOLD_INSIDE_CIRCLE',
|
||||
}
|
||||
)
|
||||
toolGroup.addToolInstance(
|
||||
'ThresholdSphere',
|
||||
BrushTool.toolName,
|
||||
{
|
||||
activeStrategy: 'THRESHOLD_INSIDE_SPHERE',
|
||||
}
|
||||
)
|
||||
toolGroup.addTool(LabelMapEditWithContourTool.toolName);
|
||||
toolGroup.addTool(SegmentBidirectionalTool.toolName, {
|
||||
getTextLines: this.getBidirectionalToolTextLines
|
||||
});
|
||||
}
|
||||
if (volumeViewportIds.includes(viewportId)) {
|
||||
toolGroup.addTool(WindowLevelTool.toolName, {
|
||||
targetViewportIds: volumeViewportIds
|
||||
})
|
||||
toolGroup.addTool(CrosshairsTool.toolName, {
|
||||
getReferenceLineColor: this.setCrosshairsToolLineColor
|
||||
});
|
||||
if (toolGroupId.includes('surface')) {
|
||||
// toolGroup.addTool(TrackballRotateTool.toolName, {
|
||||
// rotateSampleDistanceFactor: 0,
|
||||
// });
|
||||
// toolGroup.setToolActive(TrackballRotateTool.toolName, {
|
||||
// bindings: [
|
||||
// {
|
||||
// mouseButton: MouseBindings.Primary,
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
} else if (toolGroupId.includes('contour')) {
|
||||
// toolGroup.addTool(PlanarFreehandContourSegmentationTool.toolName);
|
||||
// toolGroup.addTool(SplineContourSegmentationTool.toolName);
|
||||
// toolGroup.setToolActive(PlanarFreehandContourSegmentationTool.toolName, {
|
||||
// bindings: [
|
||||
// {
|
||||
// mouseButton: MouseBindings.Primary, // Middle Click
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
} else {
|
||||
toolGroup.addTool(StackScrollTool.toolName, {
|
||||
loop: true, // 启用循环滚动
|
||||
})
|
||||
|
||||
toolGroup.addTool(ScaleOverlayTool.toolName)
|
||||
|
||||
toolGroup.addTool(PanTool.toolName)
|
||||
toolGroup.addTool(ZoomTool.toolName)
|
||||
toolGroup.addTool(BrushTool.toolName)
|
||||
if (this.readingTool === 3 || toolGroupId === this.volumeToolGroupId) {
|
||||
toolGroup.addToolInstance(
|
||||
'histogram_RectangleROI',
|
||||
RectangleROITool.toolName,
|
||||
);
|
||||
toolGroup.addToolInstance(
|
||||
'histogram_CircleROI',
|
||||
CircleROITool.toolName,
|
||||
);
|
||||
toolGroup.addToolInstance(
|
||||
'histogram_PlanarFreehandROI',
|
||||
PlanarFreehandROITool.toolName,
|
||||
);
|
||||
toolGroup.addToolInstance(
|
||||
'CircularBrush',
|
||||
BrushTool.toolName,
|
||||
{
|
||||
activeStrategy: 'FILL_INSIDE_CIRCLE',
|
||||
preview: {
|
||||
previewColors: {}
|
||||
}
|
||||
}
|
||||
);
|
||||
toolGroup.addToolInstance(
|
||||
'CircularEraser',
|
||||
BrushTool.toolName,
|
||||
{
|
||||
activeStrategy: 'ERASE_INSIDE_CIRCLE',
|
||||
preview: {
|
||||
previewColors: {}
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
toolGroup.addToolInstance(
|
||||
'ThresholdCircle',
|
||||
BrushTool.toolName,
|
||||
{
|
||||
activeStrategy: 'THRESHOLD_INSIDE_CIRCLE',
|
||||
}
|
||||
)
|
||||
toolGroup.addToolInstance(
|
||||
'ThresholdSphere',
|
||||
BrushTool.toolName,
|
||||
{
|
||||
activeStrategy: 'THRESHOLD_INSIDE_SPHERE',
|
||||
}
|
||||
)
|
||||
toolGroup.addTool(LabelMapEditWithContourTool.toolName);
|
||||
toolGroup.addTool(SegmentBidirectionalTool.toolName, {
|
||||
getTextLines: this.getBidirectionalToolTextLines
|
||||
});
|
||||
}
|
||||
if (volumeViewportIds.includes(viewportId)) {
|
||||
toolGroup.addTool(WindowLevelTool.toolName, {
|
||||
targetViewportIds: volumeViewportIds
|
||||
})
|
||||
toolGroup.addTool(CrosshairsTool.toolName, {
|
||||
getReferenceLineColor: this.setCrosshairsToolLineColor
|
||||
});
|
||||
} else {
|
||||
toolGroup.addTool(WindowLevelTool.toolName)
|
||||
}
|
||||
toolGroup.addTool(WindowLevelTool.toolName)
|
||||
}
|
||||
toolGroup.addTool(WindowLevelTool.toolName)
|
||||
toolGroup.addTool(WindowLevelRegionTool.toolName)
|
||||
toolGroup.addTool(PlanarRotateTool.toolName)
|
||||
toolGroup.addTool(ArrowAnnotateTool.toolName, {
|
||||
arrowHeadStyle: 'standard',
|
||||
changeTextCallback: async (data, eventData, doneChangingTextCallback) => {
|
||||
return doneChangingTextCallback(data.text)
|
||||
},
|
||||
getTextCallback: async (doneChangingTextCallback) => {
|
||||
return doneChangingTextCallback('Annotation')
|
||||
toolGroup.addTool(WindowLevelRegionTool.toolName)
|
||||
toolGroup.addTool(PlanarRotateTool.toolName)
|
||||
toolGroup.addTool(ArrowAnnotateTool.toolName, {
|
||||
arrowHeadStyle: 'standard',
|
||||
changeTextCallback: async (data, eventData, doneChangingTextCallback) => {
|
||||
return doneChangingTextCallback(data.text)
|
||||
},
|
||||
getTextCallback: async (doneChangingTextCallback) => {
|
||||
return doneChangingTextCallback('Annotation')
|
||||
}
|
||||
})
|
||||
toolGroup.addTool(RectangleROITool.toolName, {
|
||||
cachedStats: false,
|
||||
getTextLines: this.criterionType === 0 ? this.getCustomRectangleROIToolTextLines : this.getRectangleROIToolTextLines
|
||||
})
|
||||
toolGroup.addTool(PlanarFreehandROITool.toolName, {
|
||||
allowOpenContours: false,
|
||||
cachedStats: false,
|
||||
getTextLines: this.getPlanarFreehandROIToolTextLines
|
||||
})
|
||||
|
||||
toolGroup.addTool(EraserTool.toolName)
|
||||
toolGroup.addTool(LengthTool.toolName, {
|
||||
getTextLines: this.getLengthToolTextLines
|
||||
// cachedStats: false
|
||||
})
|
||||
toolGroup.addTool(BidirectionalTool.toolName, {
|
||||
// cachedStats: true,
|
||||
actions: this.actionConfiguration,
|
||||
getTextLines: this.getBidirectionalToolTextLines
|
||||
})
|
||||
toolGroup.addTool(CircleROITool.toolName, {
|
||||
getTextLines: this.getCircleROIToolTextLines
|
||||
})
|
||||
toolGroup.addTool(EllipticalROITool.toolName, {
|
||||
getTextLines: this.getEllipticalROIToolTextLines
|
||||
})
|
||||
toolGroup.addTool(FixedRadiusCircleROITool.toolName), {
|
||||
getTextLines: this.getCircleROIToolTextLines
|
||||
}
|
||||
})
|
||||
toolGroup.addTool(RectangleROITool.toolName, {
|
||||
cachedStats: false,
|
||||
getTextLines: this.criterionType === 0 ? this.getCustomRectangleROIToolTextLines : this.getRectangleROIToolTextLines
|
||||
})
|
||||
toolGroup.addTool(PlanarFreehandROITool.toolName, {
|
||||
allowOpenContours: false,
|
||||
cachedStats: false,
|
||||
getTextLines: this.getPlanarFreehandROIToolTextLines
|
||||
})
|
||||
|
||||
toolGroup.addTool(EraserTool.toolName)
|
||||
toolGroup.addTool(LengthTool.toolName, {
|
||||
getTextLines: this.getLengthToolTextLines
|
||||
// cachedStats: false
|
||||
})
|
||||
toolGroup.addTool(BidirectionalTool.toolName, {
|
||||
// cachedStats: true,
|
||||
actions: this.actionConfiguration,
|
||||
getTextLines: this.getBidirectionalToolTextLines
|
||||
})
|
||||
toolGroup.addTool(CircleROITool.toolName, {
|
||||
getTextLines: this.getCircleROIToolTextLines
|
||||
})
|
||||
toolGroup.addTool(EllipticalROITool.toolName, {
|
||||
getTextLines: this.getEllipticalROIToolTextLines
|
||||
})
|
||||
toolGroup.addTool(FixedRadiusCircleROITool.toolName), {
|
||||
getTextLines: this.getCircleROIToolTextLines
|
||||
}
|
||||
toolGroup.addTool(AngleTool.toolName, {
|
||||
getTextLines: this.getAngleToolTextLines
|
||||
})
|
||||
toolGroup.addTool(CobbAngleTool.toolName, {
|
||||
getTextLines: this.getCobbAngleToolTextLines
|
||||
})
|
||||
if (toolGroupId === 'viewport-fusion-3') {
|
||||
toolGroup.addTool(VolumeRotateTool.toolName)
|
||||
toolGroup.setToolActive(VolumeRotateTool.toolName, {
|
||||
bindings: [
|
||||
{
|
||||
mouseButton: MouseBindings.Wheel // mouse wheel
|
||||
}
|
||||
]
|
||||
toolGroup.addTool(AngleTool.toolName, {
|
||||
getTextLines: this.getAngleToolTextLines
|
||||
})
|
||||
toolGroup.addTool(MIPJumpToClickTool.toolName, {
|
||||
targetViewportIds: fusionViewportIds.filter((id) => id !== toolGroupId)
|
||||
toolGroup.addTool(CobbAngleTool.toolName, {
|
||||
getTextLines: this.getCobbAngleToolTextLines
|
||||
})
|
||||
if (toolGroupId === 'viewport-fusion-3') {
|
||||
toolGroup.addTool(VolumeRotateTool.toolName)
|
||||
toolGroup.setToolActive(VolumeRotateTool.toolName, {
|
||||
bindings: [
|
||||
{
|
||||
mouseButton: MouseBindings.Wheel // mouse wheel
|
||||
}
|
||||
]
|
||||
})
|
||||
toolGroup.addTool(MIPJumpToClickTool.toolName, {
|
||||
targetViewportIds: fusionViewportIds.filter((id) => id !== toolGroupId)
|
||||
})
|
||||
|
||||
// Set the initial state of the tools, here we set one tool active on left click.
|
||||
// This means left click will draw that tool.
|
||||
toolGroup.setToolActive(MIPJumpToClickTool.toolName, {
|
||||
bindings: [
|
||||
{
|
||||
mouseButton: MouseBindings.Primary // Left Click
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
toolGroup.setToolConfiguration(
|
||||
ScaleOverlayTool.toolName,
|
||||
{
|
||||
scaleLocation: 'bottom'
|
||||
},
|
||||
true // overwrite
|
||||
)
|
||||
toolGroup.setToolActive(StackScrollTool.toolName, {
|
||||
bindings: [{ mouseButton: MouseBindings.Wheel }]
|
||||
})
|
||||
toolGroup.setToolActive(ZoomTool.toolName, {
|
||||
bindings: [{ mouseButton: MouseBindings.Secondary }]
|
||||
})
|
||||
toolGroup.setToolActive(PanTool.toolName, {
|
||||
bindings: [{ mouseButton: MouseBindings.Auxiliary }]
|
||||
})
|
||||
toolGroup.setToolPassive(WindowLevelTool.toolName)
|
||||
toolGroup.setToolPassive(WindowLevelRegionTool.toolName)
|
||||
toolGroup.setToolPassive(PlanarRotateTool.toolName)
|
||||
|
||||
if (this.readingTaskState < 2) {
|
||||
toolGroup.setToolPassive(ArrowAnnotateTool.toolName)
|
||||
toolGroup.setToolPassive(RectangleROITool.toolName)
|
||||
toolGroup.setToolPassive(PlanarFreehandROITool.toolName)
|
||||
toolGroup.setToolPassive(LengthTool.toolName)
|
||||
toolGroup.setToolPassive(BidirectionalTool.toolName)
|
||||
toolGroup.setToolPassive(CircleROITool.toolName)
|
||||
toolGroup.setToolPassive(EllipticalROITool.toolName)
|
||||
toolGroup.setToolPassive(FixedRadiusCircleROITool.toolName)
|
||||
toolGroup.setToolPassive(AngleTool.toolName)
|
||||
toolGroup.setToolPassive(CobbAngleTool.toolName)
|
||||
if (this.readingTool === 3) {
|
||||
toolGroup.setToolPassive(LabelMapEditWithContourTool.toolName)
|
||||
toolGroup.setToolPassive(SegmentBidirectionalTool.toolName, {});
|
||||
// Set the initial state of the tools, here we set one tool active on left click.
|
||||
// This means left click will draw that tool.
|
||||
toolGroup.setToolActive(MIPJumpToClickTool.toolName, {
|
||||
bindings: [
|
||||
{
|
||||
mouseButton: MouseBindings.Primary // Left Click
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
} else {
|
||||
toolGroup.setToolEnabled(ArrowAnnotateTool.toolName)
|
||||
toolGroup.setToolEnabled(RectangleROITool.toolName)
|
||||
toolGroup.setToolEnabled(PlanarFreehandROITool.toolName)
|
||||
toolGroup.setToolEnabled(LengthTool.toolName)
|
||||
toolGroup.setToolEnabled(BidirectionalTool.toolName)
|
||||
toolGroup.setToolEnabled(CircleROITool.toolName)
|
||||
toolGroup.setToolEnabled(EllipticalROITool.toolName)
|
||||
toolGroup.setToolEnabled(FixedRadiusCircleROITool.toolName)
|
||||
toolGroup.setToolEnabled(AngleTool.toolName)
|
||||
toolGroup.setToolEnabled(CobbAngleTool.toolName)
|
||||
if (this.readingTool === 3) toolGroup.setToolEnabled(LabelMapEditWithContourTool.toolName)
|
||||
|
||||
toolGroup.setToolConfiguration(
|
||||
ScaleOverlayTool.toolName,
|
||||
{
|
||||
scaleLocation: 'bottom'
|
||||
},
|
||||
true // overwrite
|
||||
)
|
||||
toolGroup.setToolActive(StackScrollTool.toolName, {
|
||||
bindings: [{ mouseButton: MouseBindings.Wheel }]
|
||||
})
|
||||
toolGroup.setToolActive(ZoomTool.toolName, {
|
||||
bindings: [{ mouseButton: MouseBindings.Secondary }]
|
||||
})
|
||||
toolGroup.setToolActive(PanTool.toolName, {
|
||||
bindings: [{ mouseButton: MouseBindings.Auxiliary }]
|
||||
})
|
||||
toolGroup.setToolPassive(WindowLevelTool.toolName)
|
||||
toolGroup.setToolPassive(WindowLevelRegionTool.toolName)
|
||||
toolGroup.setToolPassive(PlanarRotateTool.toolName)
|
||||
|
||||
if (this.readingTaskState < 2) {
|
||||
toolGroup.setToolPassive(ArrowAnnotateTool.toolName)
|
||||
toolGroup.setToolPassive(RectangleROITool.toolName)
|
||||
toolGroup.setToolPassive(PlanarFreehandROITool.toolName)
|
||||
toolGroup.setToolPassive(LengthTool.toolName)
|
||||
toolGroup.setToolPassive(BidirectionalTool.toolName)
|
||||
toolGroup.setToolPassive(CircleROITool.toolName)
|
||||
toolGroup.setToolPassive(EllipticalROITool.toolName)
|
||||
toolGroup.setToolPassive(FixedRadiusCircleROITool.toolName)
|
||||
toolGroup.setToolPassive(AngleTool.toolName)
|
||||
toolGroup.setToolPassive(CobbAngleTool.toolName)
|
||||
if (this.readingTool === 3) {
|
||||
toolGroup.setToolPassive(LabelMapEditWithContourTool.toolName)
|
||||
toolGroup.setToolPassive(SegmentBidirectionalTool.toolName, {});
|
||||
}
|
||||
} else {
|
||||
toolGroup.setToolEnabled(ArrowAnnotateTool.toolName)
|
||||
toolGroup.setToolEnabled(RectangleROITool.toolName)
|
||||
toolGroup.setToolEnabled(PlanarFreehandROITool.toolName)
|
||||
toolGroup.setToolEnabled(LengthTool.toolName)
|
||||
toolGroup.setToolEnabled(BidirectionalTool.toolName)
|
||||
toolGroup.setToolEnabled(CircleROITool.toolName)
|
||||
toolGroup.setToolEnabled(EllipticalROITool.toolName)
|
||||
toolGroup.setToolEnabled(FixedRadiusCircleROITool.toolName)
|
||||
toolGroup.setToolEnabled(AngleTool.toolName)
|
||||
toolGroup.setToolEnabled(CobbAngleTool.toolName)
|
||||
if (this.readingTool === 3) toolGroup.setToolEnabled(LabelMapEditWithContourTool.toolName)
|
||||
}
|
||||
toolGroup.setToolPassive(EraserTool.toolName)
|
||||
}
|
||||
toolGroup.setToolPassive(EraserTool.toolName)
|
||||
|
||||
})
|
||||
eventTarget.addEventListener('cornerstoneimageloadprogress', this.imageLoadProgress)
|
||||
// console.log(Events, toolsEvents)
|
||||
|
|
@ -2627,7 +2716,7 @@ export default {
|
|||
viewport.render()
|
||||
renderingEngine.render()
|
||||
if (this.readingTool === 3) {
|
||||
DicomEvent.$emit('isloaded', { isChange: false })
|
||||
DicomEvent.$emit('isloaded', { isChange: false, viewportId })
|
||||
}
|
||||
},
|
||||
// 更改视图布局
|
||||
|
|
@ -2907,25 +2996,25 @@ export default {
|
|||
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resize(forceFitToWindow)
|
||||
},
|
||||
// 重置视口
|
||||
resetRenderingEngine(viewportId = null) {
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer)
|
||||
this.timer = null
|
||||
resetRenderingEngine(viewportId = null, i) {
|
||||
if (this.timer[viewportId]) {
|
||||
clearInterval(this.timer[viewportId])
|
||||
this.timer[viewportId] = null
|
||||
}
|
||||
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||
const viewport = renderingEngine.getViewport(viewportId)
|
||||
if (!viewport) return false
|
||||
if (viewport.volumeIds.size <= 0) return false
|
||||
let index = null
|
||||
this.timer = setTimeout(() => {
|
||||
index = index || index === 0 ? index : this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].series.SliceIndex
|
||||
this.timer[viewportId] = setTimeout(() => {
|
||||
index = i || i === 0 ? i : this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].series.SliceIndex
|
||||
renderingEngine.resize(true, false)
|
||||
renderingEngine.render()
|
||||
this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].setFullScreen(index)
|
||||
clearTimeout(this.timer)
|
||||
this.timer = null
|
||||
clearTimeout(this.timer[viewportId])
|
||||
this.timer[viewportId] = null
|
||||
if (this.readingTool === 3) {
|
||||
DicomEvent.$emit('isloaded', { isChange: false })
|
||||
DicomEvent.$emit('isloaded', { isChange: false, viewportId })
|
||||
}
|
||||
}, 100)
|
||||
},
|
||||
|
|
@ -2946,7 +3035,7 @@ export default {
|
|||
if (this.readingTool === 3 || this.isMPR) {
|
||||
// this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series)
|
||||
this.$nextTick(() => {
|
||||
this.resetRenderingEngine()
|
||||
// this.resetRenderingEngine(`${this.viewportKey}-${index}`)
|
||||
this.isDelay = true
|
||||
this.setDelay(2000)
|
||||
// if (this.readingTool === 3) {
|
||||
|
|
@ -4048,8 +4137,13 @@ export default {
|
|||
this.saveCustomAnnotationTimer = null
|
||||
}
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer)
|
||||
this.timer = null
|
||||
Object.keys(this.timer).forEach(key => {
|
||||
if (this.timer[key]) {
|
||||
clearInterval(this.timer[key])
|
||||
this.timer[key] = null
|
||||
}
|
||||
})
|
||||
this.timer = {}
|
||||
}
|
||||
if (this.FullTimerOut) {
|
||||
clearTimeout(this.FullTimerOut)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@
|
|||
@click.stop="changeShowSegmentConfig" />
|
||||
</div>
|
||||
</template>
|
||||
<div class="addSegmentBox viewHover" @click.stop="addSegment" v-if="segmentList.length <= 0">
|
||||
<div class="addSegmentBox viewHover" @click.stop="addSegment"
|
||||
v-if="segmentList.length <= 0 && readingTaskState < 2">
|
||||
<span><i class="el-icon-plus"></i>
|
||||
{{ $t('trials:reading:Segmentations:button:addSegmention') }}
|
||||
</span>
|
||||
|
|
@ -124,16 +125,11 @@
|
|||
$t('trials:reading:Segmentations:title:InactiveSegmentationsShow')
|
||||
}}</span>
|
||||
</div>
|
||||
<!-- <div class="SegmentConfig" v-if="SegmentConfig.InactiveSegmentations.show">
|
||||
<span>{{ $t('trials:reading:Segmentations:title:Opacity') }}</span>
|
||||
<el-slider v-model="SegmentConfig.InactiveSegmentations.fillAlpha" show-input :step="0.1"
|
||||
:max="1" input-size="mini" :show-input-controls="false" />
|
||||
</div> -->
|
||||
</div>
|
||||
<template v-if="segmentList.length > 0">
|
||||
<div class="SegmentGroupBox">
|
||||
<div style="display: flex;align-items: center;">
|
||||
<el-popover placement="left" width="40" trigger="click">
|
||||
<el-popover placement="left" width="40" trigger="click" v-if="readingTaskState < 2">
|
||||
<div class="SegmentGroupBtnBox">
|
||||
<div class="SegmentGroupBtn" @click.stop="addSegmentGroup">
|
||||
{{ $t('trials:reading:Segmentations:button:addSegmentGroup') }}
|
||||
|
|
@ -156,7 +152,7 @@
|
|||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div style="display: flex;align-items: center;">
|
||||
<div style="display: flex;align-items: center;" v-if="readingTaskState < 2">
|
||||
<i class="el-icon-warning-outline" style="color:red;margin-right: 5px;"
|
||||
:title="$t('trials:reading:Segmentations:tip:segmentationIsNotSave')"
|
||||
v-if="!curSegmentGroup.isSaved"></i>
|
||||
|
|
@ -167,7 +163,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="addSegmentBox" @click.stop="addSegment"
|
||||
style="display: flex;align-items: center;justify-content: space-between;">
|
||||
style="display: flex;align-items: center;justify-content: space-between;"
|
||||
v-if="readingTaskState < 2">
|
||||
<span><i class="el-icon-plus"></i>
|
||||
{{ $t('trials:reading:Segmentations:button:addSegment') }}
|
||||
</span>
|
||||
|
|
@ -220,7 +217,7 @@
|
|||
<i class="el-icon-lock" v-if="item.lock" @click.stop="lockSegment(item, false)"></i>
|
||||
<el-popover placement="bottom" width="40" trigger="click" class="docShow"
|
||||
:value="popoverId === `popover-${item.segmentationId}_${item.segmentIndex}`"
|
||||
@show="handleClickPopover(item)">
|
||||
@show="handleClickPopover(item)" v-if="readingTaskState < 2">
|
||||
<div class="SegmentGroupBtnBox">
|
||||
<div class="SegmentGroupBtn" @click.stop="rename('segment', item)">
|
||||
{{ $t('trials:reading:Segmentations:button:renameSegmentGroup') }}
|
||||
|
|
@ -245,7 +242,7 @@
|
|||
</template>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<div class="saveBtnBox">
|
||||
<div class="saveBtnBox" v-if="readingTaskState < 2">
|
||||
<el-button type="success" size="small" :disabled="saveLoading" @click="saveSegmentGroup()">
|
||||
{{ $t("trials:reading:Segmentations:button:saveAll") }}
|
||||
</el-button>
|
||||
|
|
@ -261,6 +258,8 @@ import * as cornerstoneAdapters from "@cornerstonejs/adapters";
|
|||
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
|
||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||
import { getCustomizeStandardsSegmentDicomTools } from './toolConfig'
|
||||
import * as polySeg from '@cornerstonejs/polymorphic-segmentation'
|
||||
cornerstoneTools.init({ addons: { polySeg } })
|
||||
const {
|
||||
ToolGroupManager,
|
||||
Enums: csToolsEnums,
|
||||
|
|
@ -271,6 +270,7 @@ const {
|
|||
CrosshairsTool,
|
||||
utilities: CStUtils,
|
||||
} = cornerstoneTools;
|
||||
|
||||
const { MouseBindings, Events: toolsEvents } = csToolsEnums
|
||||
const { segmentation: segmentationUtils } = CStUtils;
|
||||
const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone;
|
||||
|
|
@ -305,12 +305,32 @@ export default {
|
|||
return {}
|
||||
}
|
||||
},
|
||||
SegmentConfig: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
actionConfiguration: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
curSegSeries: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
segId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
segIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
renderingEngineId: {
|
||||
type: String,
|
||||
required: true
|
||||
|
|
@ -343,16 +363,6 @@ export default {
|
|||
ThresholdTools: ['ThresholdCircle', 'ThresholdSphere'],
|
||||
thresholdType: null,
|
||||
showSegmentConfig: false,
|
||||
SegmentConfig: {
|
||||
renderOutline: true,
|
||||
renderFill: true,
|
||||
fillAlpha: 0.5,
|
||||
outlineWidth: 1,
|
||||
InactiveSegmentations: {
|
||||
show: true,
|
||||
fillAlpha: 0.3,
|
||||
}
|
||||
},
|
||||
segmentList: [],
|
||||
segmentationId: "",
|
||||
segmentIndex: null,
|
||||
|
|
@ -368,7 +378,7 @@ export default {
|
|||
'#ff994d',
|
||||
'#fb628b',
|
||||
],
|
||||
viewprotIds: ['viewport-0', 'viewport-1', 'viewport-2', 'viewport-3', 'viewport-MPR-0', 'viewport-MPR-1', 'viewport-MPR-2'], //
|
||||
viewportIds: [], //
|
||||
statsKey: [],
|
||||
drawing: false, // 是否正在分割
|
||||
// isDel: false,
|
||||
|
|
@ -388,14 +398,24 @@ export default {
|
|||
this.segmentationModifiedCallback
|
||||
);
|
||||
DicomEvent.$on('activeSeries', (series) => {
|
||||
console.log(series, 'series')
|
||||
let { TaskInfo = {}, Id } = series
|
||||
if (Id === this.series.Id && TaskInfo.VisitTaskId === this.visitInfo.VisitTaskId) return false
|
||||
this.series = series
|
||||
this.$emit("update:curSegSeries", Object.assign(series, {}))
|
||||
this.getSegmentationList()
|
||||
})
|
||||
DicomEvent.$on('isloaded', (data) => {
|
||||
if (this.isloaded) return false
|
||||
this.isloaded = true
|
||||
let { segment, isChange = true } = data
|
||||
this.delAllSegment(isChange)
|
||||
this.getSegmentationList(segment)
|
||||
let { segment, isChange = true, viewportId, series } = data
|
||||
DicomEvent.$emit('renderSegmentation', viewportId)
|
||||
// if (!series.TaskInfo || series.TaskInfo.VisitTaskId !== this.visitInfo.VisitTaskId) return false
|
||||
// if (this.isloaded) return false
|
||||
// this.isloaded = true
|
||||
// this.series = series
|
||||
// this.viewportIds = []
|
||||
// this.viewportIds.push(viewportId)
|
||||
// // this.delAllSegment(isChange)
|
||||
// this.readingSegmentToViewport(segment)
|
||||
})
|
||||
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
||||
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
||||
|
|
@ -414,12 +434,15 @@ export default {
|
|||
s = this.curSegmentGroup.segments.find(item => item.segmentIndex === this.segmentIndex)
|
||||
}
|
||||
return s
|
||||
},
|
||||
readingTaskState() {
|
||||
return this.series.TaskInfo ? this.series.TaskInfo.ReadingTaskState : 0
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
SegmentConfig: {
|
||||
handler() {
|
||||
this.readingSegmentByConfig()
|
||||
// this.readingSegmentByConfig()
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
|
|
@ -434,9 +457,23 @@ export default {
|
|||
this.setBrushThreshold()
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
segmentIndex() {
|
||||
this.$emit('update:segIndex', this.segmentIndex)
|
||||
},
|
||||
segmentationId() {
|
||||
this.$emit('update:segId', this.segmentationId)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showSurface(item) {
|
||||
this.$emit("showSurface", {
|
||||
segmentationId: item.segmentationId,
|
||||
segmentIndex: item.segmentIndex,
|
||||
volumeId: this.series.SeriesInstanceUid,
|
||||
segmentations: this.curSegmentGroup
|
||||
})
|
||||
},
|
||||
handleClickPopover(item) {
|
||||
this.popoverId = `popover-${item.segmentationId}_${item.segmentIndex}`
|
||||
},
|
||||
|
|
@ -504,7 +541,6 @@ export default {
|
|||
segmentationId: list[0].segmentationId,
|
||||
segmentIndices: list.map(item => item.segmentIndex),
|
||||
});
|
||||
console.log(bidirectionalData, list[0].segmentationId, 'bidirectionalData')
|
||||
if (bidirectionalData.length <= 0) {
|
||||
list.forEach(item => {
|
||||
let annotations = annotation.state.getAllAnnotations().filter(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex);
|
||||
|
|
@ -563,6 +599,7 @@ export default {
|
|||
|
||||
},
|
||||
setToolActive(toolName) {
|
||||
// if (!this.series.TaskInfo || this.series.TaskInfo.VisitTaskId !== this.visitInfo.VisitTaskId) return false
|
||||
if (this.segmentList.length <= 0) return false
|
||||
if (this.curSegment.lock) return false
|
||||
if (this.histogramVisible && !this.ThresholdTools.includes(toolName)) return false
|
||||
|
|
@ -602,71 +639,33 @@ export default {
|
|||
viewBidirectional(arr, view) {
|
||||
for (let j = 0; j < arr.length; j++) {
|
||||
let item = arr[j]
|
||||
let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||
item.bidirectionalView = view
|
||||
if (!bidirectional) continue
|
||||
annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view)
|
||||
// let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||
// item.bidirectionalView = view
|
||||
// if (!bidirectional) continue
|
||||
// annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view)
|
||||
}
|
||||
this.resetViewport()
|
||||
DicomEvent.$emit('viewBidirectional', arr)
|
||||
// this.resetViewport()
|
||||
},
|
||||
async jumpBidirectional(item) {
|
||||
if (item.bidirectional) {
|
||||
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||
console.log(an, 'an')
|
||||
if (!an) return false
|
||||
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
|
||||
const viewport = renderingEngine.getViewport(viewportId)
|
||||
let key = Object.keys(an.data.cachedStats)[0]; // referencedImageId
|
||||
if (key) {
|
||||
let sliceIndex = key.split("?")[1].split("&")[0].split("=")[1]
|
||||
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIndex });
|
||||
} else {
|
||||
const points = an.data.handles.points;
|
||||
const worldPoint = points[0]; // 取一个点
|
||||
let volume = cache.getVolume(this.series.SeriesInstanceUid)
|
||||
let { imageData, numFrames } = volume
|
||||
const ijk = imageData.worldToIndex(worldPoint);
|
||||
const sliceIndex = Math.abs(Math.round(ijk[2]));
|
||||
// console.log(sliceIndex, 'sliceIndex')
|
||||
csUtils.jumpToSlice(viewport.element, { imageIndex: numFrames - sliceIndex - 1 });
|
||||
}
|
||||
|
||||
}
|
||||
DicomEvent.$emit('jumpBidirectional', item)
|
||||
},
|
||||
viewSegmentGroup(item) {
|
||||
let view = !item.view
|
||||
this.viewprotIds.forEach(id => {
|
||||
segmentation.config.visibility.setSegmentationRepresentationVisibility(
|
||||
id,
|
||||
{
|
||||
segmentationId: item.segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||
},
|
||||
view
|
||||
);
|
||||
})
|
||||
item.view = view
|
||||
|
||||
item.view = !item.view
|
||||
item.segments.forEach(i => {
|
||||
i.view = view
|
||||
// this.viewBidirectional(i, view)
|
||||
i.view = item.view
|
||||
})
|
||||
this.viewBidirectional(item.segments, view)
|
||||
DicomEvent.$emit('viewSegmentation', item)
|
||||
// this.viewBidirectional(item.segments, view)
|
||||
},
|
||||
viewSegment(item, view) {
|
||||
this.viewprotIds.forEach(id => {
|
||||
segmentation.config.visibility.setSegmentIndexVisibility(id, {
|
||||
segmentationId: item.segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||
}, item.segmentIndex, view)
|
||||
})
|
||||
item.view = view
|
||||
this.viewBidirectional([item], view)
|
||||
this.$emit('setToolsPassive')
|
||||
DicomEvent.$emit('viewSegment', item)
|
||||
},
|
||||
lockSegment(item, lock) {
|
||||
if (this.readingTaskState >= 2) return false
|
||||
segmentation.segmentLocking.setSegmentIndexLocked(item.segmentationId, item.segmentIndex, lock)
|
||||
item.lock = lock
|
||||
if (!lock) this.changeSegmentationSavedStatus(item.segmentationId, lock)
|
||||
|
|
@ -676,7 +675,7 @@ export default {
|
|||
this.segmentationId = item.segmentationId;
|
||||
this.segmentIndex = item.segmentIndex;
|
||||
}
|
||||
segmentation.segmentIndex.setActiveSegmentIndex(item.segmentationId, item.segmentIndex);
|
||||
// segmentation.segmentIndex.setActiveSegmentIndex(item.segmentationId, item.segmentIndex);
|
||||
if (isChange) { this.jumpBidirectional(item) }
|
||||
|
||||
if (item.lock) {
|
||||
|
|
@ -685,15 +684,14 @@ export default {
|
|||
// this.resetViewport()
|
||||
},
|
||||
selectSegmentGroup(s) {
|
||||
this.viewprotIds.forEach(id => {
|
||||
segmentation.activeSegmentation.setActiveSegmentation(id, this.segmentationId)
|
||||
})
|
||||
// segmentation.activeSegmentation.setActiveSegmentation(`${this.viewportKey}-${this.activeViewportIndex}`, this.segmentationId)
|
||||
let segment = s ? s : this.segmentList.find(item => item.segmentationId === this.segmentationId).segments[0]
|
||||
this.selectSegment(segment, s ? false : true)
|
||||
this.readingSegmentByConfig()
|
||||
this.segmentIndex = segment.segmentIndex
|
||||
// this.selectSegment(segment, s ? false : true)
|
||||
// this.readingSegmentByConfig()
|
||||
},
|
||||
async addSegmentGroup() {
|
||||
let viewprotIds = this.viewprotIds
|
||||
let viewportIds = this.viewportIds
|
||||
// let segmentationId = this.$guid();
|
||||
let obj = {
|
||||
name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + (this.segmentList.length + 1),
|
||||
|
|
@ -723,13 +721,14 @@ export default {
|
|||
await this.createSegmentation(obj.segmentationId)
|
||||
this.createSegmentationRepresentation(obj.segmentationId)
|
||||
this.segmentIndex = 1
|
||||
viewprotIds.forEach(id => {
|
||||
segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, 1, this.hex2Rgb(this.colors[0]))
|
||||
})
|
||||
this.changeColor(this.colors[0], { segmentationId: obj.segmentationId, segmentIndex: 1, color: this.colors[0] })
|
||||
// viewportIds.forEach(id => {
|
||||
// segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, 1, this.hex2Rgb(this.colors[0]))
|
||||
// })
|
||||
this.selectSegmentGroup()
|
||||
},
|
||||
async addSegment() {
|
||||
let viewprotIds = this.viewprotIds;
|
||||
let viewportIds = this.viewportIds;
|
||||
if (this.segmentList.length <= 0) {
|
||||
let obj = {
|
||||
name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + 1,
|
||||
|
|
@ -759,10 +758,11 @@ export default {
|
|||
this.createSegmentationRepresentation(this.segmentationId)
|
||||
this.segmentIndex = 1
|
||||
segmentation.segmentIndex.setActiveSegmentIndex(this.segmentList[0].segmentationId, 1);
|
||||
viewprotIds.forEach(id => {
|
||||
segmentation.config.color.setSegmentIndexColor(id, this.segmentList[0].segmentationId, 1, this.hex2Rgb(this.colors[0]))
|
||||
})
|
||||
this.readingSegmentByConfig()
|
||||
this.changeColor(this.colors[0], { segmentationId: this.segmentList[0].segmentationId, segmentIndex: 1, color: this.colors[0] })
|
||||
// viewportIds.forEach(id => {
|
||||
// segmentation.config.color.setSegmentIndexColor(id, this.segmentList[0].segmentationId, 1, this.hex2Rgb(this.colors[0]))
|
||||
// })
|
||||
// this.readingSegmentByConfig()
|
||||
|
||||
} else {
|
||||
let item = this.segmentList.find(i => i.segmentationId === this.segmentationId)
|
||||
|
|
@ -787,19 +787,22 @@ export default {
|
|||
let id = await this.addOrUpdateSegment({ name: obj.SegmentLabel, color: obj.color, segmentIndex: obj.segmentIndex, segmentationId: obj.segmentationId })
|
||||
obj.id = id
|
||||
item.segments.push(obj)
|
||||
segmentation.segmentIndex.setActiveSegmentIndex(obj.segmentationId, obj.segmentIndex);
|
||||
viewprotIds.forEach(id => {
|
||||
segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, obj.segmentIndex, this.hex2Rgb(obj.color))
|
||||
})
|
||||
this.segmentIndex = obj.segmentIndex
|
||||
segmentation.segmentIndex.setActiveSegmentIndex(obj.segmentationId, obj.segmentIndex);
|
||||
this.changeColor(obj.color, { segmentationId: obj.segmentationId, segmentIndex: obj.segmentIndex, color: obj.color })
|
||||
// viewportIds.forEach(id => {
|
||||
// segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, obj.segmentIndex, this.hex2Rgb(obj.color))
|
||||
// })
|
||||
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
changeColor(e, item) {
|
||||
this.viewprotIds.forEach(id => {
|
||||
segmentation.config.color.setSegmentIndexColor(id, item.segmentationId, item.segmentIndex, this.hex2Rgb(e))
|
||||
})
|
||||
DicomEvent.$emit('changeColor', item)
|
||||
// this.viewportIds.forEach(id => {
|
||||
// segmentation.config.color.setSegmentIndexColor(id, item.segmentationId, item.segmentIndex, this.hex2Rgb(e))
|
||||
// })
|
||||
},
|
||||
// 清空所有分割
|
||||
delAllSegment(isChange) {
|
||||
|
|
@ -836,7 +839,7 @@ export default {
|
|||
} else {
|
||||
this.segmentationId = ''
|
||||
}
|
||||
this.readingSegmentByConfig()
|
||||
// this.readingSegmentByConfig()
|
||||
this.resetViewport()
|
||||
this.$emit('resetQuestion')
|
||||
},
|
||||
|
|
@ -868,11 +871,7 @@ export default {
|
|||
|
||||
},
|
||||
resetViewport(passive = true) {
|
||||
let renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
this.viewprotIds.forEach(id => {
|
||||
const viewport = renderingEngine.getViewport(id)
|
||||
viewport.render()
|
||||
})
|
||||
DicomEvent.$emit('resetViewport')
|
||||
if (passive) this.$emit('setToolsPassive')
|
||||
},
|
||||
async rename(key, item) {
|
||||
|
|
@ -925,7 +924,7 @@ export default {
|
|||
// 切换非当前分组分割标记显示
|
||||
changeInactiveSegmentShow() {
|
||||
let segmentList = this.segmentList.filter(item => item.segmentationId !== this.segmentationId)
|
||||
this.viewprotIds.forEach(id => {
|
||||
this.viewportIds.forEach(id => {
|
||||
segmentation.config.visibility.setSegmentationRepresentationVisibility(
|
||||
id,
|
||||
{
|
||||
|
|
@ -967,113 +966,118 @@ export default {
|
|||
this.exportSegmentation(this.segmentationId, group, true)
|
||||
},
|
||||
exportSegmentation(segmentationId, group, isFile = false) {
|
||||
const segmentationIds = segmentation.state
|
||||
.getSegmentations()
|
||||
.map(x => x.segmentationId);
|
||||
if (!segmentationIds.length) {
|
||||
return;
|
||||
}
|
||||
const segmentGroup =
|
||||
segmentation.state.getSegmentation(segmentationId);
|
||||
|
||||
let { imageIds } = segmentGroup.representationData.Labelmap;
|
||||
|
||||
let segImages = imageIds.map(imageId => cache.getImage(imageId));
|
||||
segImages = segImages.reverse()
|
||||
let referencedImages = segImages.map(image =>
|
||||
cache.getImage(image.referencedImageId)
|
||||
);
|
||||
const labelmaps2D = [];
|
||||
|
||||
let z = 0;
|
||||
|
||||
for (const segImage of segImages) {
|
||||
const segmentsOnLabelmap = new Set();
|
||||
const pixelData = segImage.getPixelData();
|
||||
const { rows, columns } = segImage;
|
||||
|
||||
for (let i = 0; i < pixelData.length; i++) {
|
||||
const segment = pixelData[i];
|
||||
if (segment !== 0) {
|
||||
segmentsOnLabelmap.add(segment);
|
||||
}
|
||||
try {
|
||||
const segmentationIds = segmentation.state
|
||||
.getSegmentations()
|
||||
.map(x => x.segmentationId);
|
||||
if (!segmentationIds.length) {
|
||||
return;
|
||||
}
|
||||
const segmentGroup =
|
||||
segmentation.state.getSegmentation(segmentationId);
|
||||
|
||||
labelmaps2D[z++] = {
|
||||
segmentsOnLabelmap: Array.from(segmentsOnLabelmap),
|
||||
pixelData,
|
||||
rows,
|
||||
columns
|
||||
};
|
||||
}
|
||||
let { imageIds } = segmentGroup.representationData.Labelmap;
|
||||
|
||||
const allSegmentsOnLabelmap = labelmaps2D.map(
|
||||
labelmap => labelmap.segmentsOnLabelmap
|
||||
);
|
||||
|
||||
const labelmap3D = {
|
||||
segmentsOnLabelmap: Array.from(new Set(allSegmentsOnLabelmap.flat())),
|
||||
metadata: [],
|
||||
labelmaps2D
|
||||
};
|
||||
let segmentIndexs = []
|
||||
labelmap3D.segmentsOnLabelmap.forEach(segmentIndex => {
|
||||
const color = segmentation.config.color.getSegmentIndexColor(
|
||||
`${this.viewportKey}-${this.activeViewportIndex}`,
|
||||
segmentationId,
|
||||
segmentIndex
|
||||
let segImages = imageIds.map(imageId => cache.getImage(imageId));
|
||||
segImages = segImages.reverse()
|
||||
let referencedImages = segImages.map(image =>
|
||||
cache.getImage(image.referencedImageId)
|
||||
);
|
||||
const RecommendedDisplayCIELabValue = dcmjs.data.Colors.rgb2DICOMLAB(
|
||||
color.slice(0, 3).map(value => value / 255)
|
||||
).map(value => Math.round(value));
|
||||
let segment = group.segments.find(item => item.segmentIndex === segmentIndex)
|
||||
if (segment) {
|
||||
segmentIndexs.push(segmentIndex)
|
||||
let SegmentLabel = segment.SegmentLabel
|
||||
const segmentMetadata = {
|
||||
SegmentNumber: segmentIndex.toString(),
|
||||
SegmentLabel: SegmentLabel,
|
||||
SegmentAlgorithmType: "MANUAL",
|
||||
SegmentAlgorithmName: "OHIF Brush",
|
||||
RecommendedDisplayCIELabValue,
|
||||
SegmentedPropertyCategoryCodeSequence: {
|
||||
CodeValue: "T-D0050",
|
||||
CodingSchemeDesignator: "SRT",
|
||||
CodeMeaning: "Tissue"
|
||||
},
|
||||
SegmentedPropertyTypeCodeSequence: {
|
||||
CodeValue: "T-D0050",
|
||||
CodingSchemeDesignator: "SRT",
|
||||
CodeMeaning: "Tissue"
|
||||
const labelmaps2D = [];
|
||||
|
||||
let z = 0;
|
||||
|
||||
for (const segImage of segImages) {
|
||||
const segmentsOnLabelmap = new Set();
|
||||
const pixelData = segImage.getPixelData();
|
||||
const { rows, columns } = segImage;
|
||||
|
||||
for (let i = 0; i < pixelData.length; i++) {
|
||||
const segment = pixelData[i];
|
||||
if (segment !== 0) {
|
||||
segmentsOnLabelmap.add(segment);
|
||||
}
|
||||
}
|
||||
|
||||
labelmaps2D[z++] = {
|
||||
segmentsOnLabelmap: Array.from(segmentsOnLabelmap),
|
||||
pixelData,
|
||||
rows,
|
||||
columns
|
||||
};
|
||||
|
||||
if (segment.stats) labelmap3D.metadata[segmentIndex] = segmentMetadata;
|
||||
}
|
||||
});
|
||||
if (labelmap3D.metadata.length <= 0) {
|
||||
return false
|
||||
}
|
||||
const generatedSegmentation =
|
||||
Cornerstone3D.Segmentation.generateSegmentation(
|
||||
referencedImages,
|
||||
labelmap3D,
|
||||
metaData
|
||||
|
||||
const allSegmentsOnLabelmap = labelmaps2D.map(
|
||||
labelmap => labelmap.segmentsOnLabelmap
|
||||
);
|
||||
segmentIndexs.forEach((item, index) => {
|
||||
if (generatedSegmentation.dataset.SegmentSequence[index]) {
|
||||
generatedSegmentation.dataset.SegmentSequence[index].SegmentNumber = item.toString()
|
||||
}
|
||||
|
||||
})
|
||||
generatedSegmentation.dataset.SegmentSequence.sort((a, b) => a.SegmentNumber - b.SegmentNumber)
|
||||
if (!isFile) {
|
||||
const buffer = Buffer.from(dcmjs.data.datasetToDict(generatedSegmentation.dataset).write());
|
||||
let blob = new Blob([buffer], { type: "application/dicom" });
|
||||
return blob
|
||||
} else {
|
||||
this.downloadDICOMData(generatedSegmentation.dataset, `${group.name}.dcm`);
|
||||
const labelmap3D = {
|
||||
segmentsOnLabelmap: Array.from(new Set(allSegmentsOnLabelmap.flat())),
|
||||
metadata: [],
|
||||
labelmaps2D
|
||||
};
|
||||
let segmentIndexs = []
|
||||
labelmap3D.segmentsOnLabelmap.forEach(segmentIndex => {
|
||||
const color = segmentation.config.color.getSegmentIndexColor(
|
||||
`${this.viewportKey}-${this.activeViewportIndex}`,
|
||||
segmentationId,
|
||||
segmentIndex
|
||||
);
|
||||
const RecommendedDisplayCIELabValue = dcmjs.data.Colors.rgb2DICOMLAB(
|
||||
color.slice(0, 3).map(value => value / 255)
|
||||
).map(value => Math.round(value));
|
||||
let segment = group.segments.find(item => item.segmentIndex === segmentIndex)
|
||||
if (segment) {
|
||||
segmentIndexs.push(segmentIndex)
|
||||
let SegmentLabel = segment.SegmentLabel
|
||||
const segmentMetadata = {
|
||||
SegmentNumber: segmentIndex.toString(),
|
||||
SegmentLabel: SegmentLabel,
|
||||
SegmentAlgorithmType: "MANUAL",
|
||||
SegmentAlgorithmName: "OHIF Brush",
|
||||
RecommendedDisplayCIELabValue,
|
||||
SegmentedPropertyCategoryCodeSequence: {
|
||||
CodeValue: "T-D0050",
|
||||
CodingSchemeDesignator: "SRT",
|
||||
CodeMeaning: "Tissue"
|
||||
},
|
||||
SegmentedPropertyTypeCodeSequence: {
|
||||
CodeValue: "T-D0050",
|
||||
CodingSchemeDesignator: "SRT",
|
||||
CodeMeaning: "Tissue"
|
||||
}
|
||||
};
|
||||
|
||||
if (segment.stats) labelmap3D.metadata[segmentIndex] = segmentMetadata;
|
||||
}
|
||||
});
|
||||
if (labelmap3D.metadata.length <= 0) {
|
||||
return false
|
||||
}
|
||||
const generatedSegmentation =
|
||||
Cornerstone3D.Segmentation.generateSegmentation(
|
||||
referencedImages,
|
||||
labelmap3D,
|
||||
metaData
|
||||
);
|
||||
segmentIndexs.forEach((item, index) => {
|
||||
if (generatedSegmentation.dataset.SegmentSequence[index]) {
|
||||
generatedSegmentation.dataset.SegmentSequence[index].SegmentNumber = item.toString()
|
||||
}
|
||||
|
||||
})
|
||||
generatedSegmentation.dataset.SegmentSequence.sort((a, b) => a.SegmentNumber - b.SegmentNumber)
|
||||
if (!isFile) {
|
||||
const buffer = Buffer.from(dcmjs.data.datasetToDict(generatedSegmentation.dataset).write());
|
||||
let blob = new Blob([buffer], { type: "application/dicom" });
|
||||
return blob
|
||||
} else {
|
||||
this.downloadDICOMData(generatedSegmentation.dataset, `${group.name}.dcm`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
},
|
||||
downloadDICOMData(bufferOrDataset, filename) {
|
||||
let blob;
|
||||
|
|
@ -1123,7 +1127,7 @@ export default {
|
|||
|
||||
const arrayBuffer = image.data.byteArray.buffer;
|
||||
await this.loadSegmentation(arrayBuffer, obj.segmentationId);
|
||||
this.createSegmentationRepresentation(obj.segmentationId);
|
||||
// this.createSegmentationRepresentation(obj.segmentationId);
|
||||
},
|
||||
async loadSegmentation(arrayBuffer, segmentationId) {
|
||||
const generateToolState =
|
||||
|
|
@ -1306,51 +1310,49 @@ export default {
|
|||
}
|
||||
},
|
||||
createSegmentationRepresentation(segmentationId) {
|
||||
this.viewprotIds.forEach(id => {
|
||||
segmentation.addSegmentationRepresentations(id, [
|
||||
{
|
||||
segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||
},
|
||||
])
|
||||
})
|
||||
DicomEvent.$emit('createSegmentationRepresentation', segmentationId)
|
||||
this.$emit('setToolsPassive')
|
||||
},
|
||||
contentMouseup() {
|
||||
// console.log("segment contentMouseup")
|
||||
if (!this.drawing) return false
|
||||
if (this.timeoutId) {
|
||||
clearTimeout(this.timeoutId);
|
||||
this.timeoutId = null;
|
||||
}
|
||||
this.timeoutId = setTimeout(() => {
|
||||
this.timeoutId = null;
|
||||
this.drawing = false;
|
||||
let segmentGroup = this.segmentList.find(item => item.segmentationId === this.segmentationId)
|
||||
if (segmentGroup && segmentGroup.segments && segmentGroup.segments.length > 0) {
|
||||
let segmentIndexs = []
|
||||
segmentGroup.segments.forEach(item => {
|
||||
segmentIndexs.push(item.segmentIndex)
|
||||
item.bidirectional = null
|
||||
item.stats = null
|
||||
})
|
||||
annotation.state.getAllAnnotations().forEach(i => {
|
||||
if (i.metadata.segmentationId === this.segmentationId && i.metadata.toolName === "SegmentBidirectional") {
|
||||
annotation.state.removeAnnotation(i.annotationUID)
|
||||
}
|
||||
})
|
||||
this.calculateStatistics(segmentIndexs, this.segmentationId, 'individual');
|
||||
this.resetViewport(false)
|
||||
// this.getBidirectional(segmentGroup.segments)
|
||||
|
||||
try {
|
||||
// console.log("segment contentMouseup")
|
||||
if (!this.drawing) return false
|
||||
if (this.timeoutId) {
|
||||
clearTimeout(this.timeoutId);
|
||||
this.timeoutId = null;
|
||||
}
|
||||
}, 500);
|
||||
this.timeoutId = setTimeout(() => {
|
||||
this.timeoutId = null;
|
||||
this.drawing = false;
|
||||
let segmentGroup = this.segmentList.find(item => item.segmentationId === this.segmentationId)
|
||||
if (segmentGroup && segmentGroup.segments && segmentGroup.segments.length > 0) {
|
||||
let segmentIndexs = []
|
||||
segmentGroup.segments.forEach(item => {
|
||||
segmentIndexs.push(item.segmentIndex)
|
||||
item.bidirectional = null
|
||||
item.stats = null
|
||||
})
|
||||
annotation.state.getAllAnnotations().forEach(i => {
|
||||
if (i.metadata.segmentationId === this.segmentationId && i.metadata.toolName === "SegmentBidirectional") {
|
||||
annotation.state.removeAnnotation(i.annotationUID)
|
||||
}
|
||||
})
|
||||
this.calculateStatistics(segmentIndexs, this.segmentationId, 'individual');
|
||||
this.resetViewport(false)
|
||||
// this.getBidirectional(segmentGroup.segments)
|
||||
|
||||
}
|
||||
}, 500);
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
},
|
||||
// 获取当前任务分割标记与问题绑定关系
|
||||
async getSegmentBindingList(param = {}) {
|
||||
try {
|
||||
let data = {
|
||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
||||
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||
PageSize: 9999,
|
||||
PageIndex: 1,
|
||||
}
|
||||
|
|
@ -1367,7 +1369,7 @@ export default {
|
|||
async saveSegmentBindingAndAnswer(list) {
|
||||
try {
|
||||
let data = {
|
||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
||||
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||
BindingList: list
|
||||
}
|
||||
let res = await saveSegmentBindingAndAnswer(data)
|
||||
|
|
@ -1482,7 +1484,7 @@ export default {
|
|||
|
||||
let bidirectional = bidirectionalData[0]
|
||||
const { segmentIndex } = bidirectional;
|
||||
const { majorAxis, minorAxis, maxMajor, maxMinor } = bidirectional;
|
||||
const { majorAxis, minorAxis } = bidirectional;
|
||||
let item = list.find(i => i.segmentIndex === segmentIndex)
|
||||
SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], {
|
||||
segmentIndex,
|
||||
|
|
@ -1491,7 +1493,7 @@ export default {
|
|||
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||
if (an) {
|
||||
annotation.locking.setAnnotationLocked(an.annotationUID, true)
|
||||
annotation.visibility.setAnnotationVisibility(an.annotationUID, item.bidirectionalView)
|
||||
annotation.visibility.setAnnotationVisibility(an.annotationUID, true)
|
||||
}
|
||||
item.bidirectional = bidirectional
|
||||
reslove(true)
|
||||
|
|
@ -1536,7 +1538,7 @@ export default {
|
|||
SegmentId: item.SegmentId,
|
||||
SegmentationId: item.SegmentationId,
|
||||
TableQuestionId: item.TableQuestionId,
|
||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
||||
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||
}
|
||||
bindingList.push(o)
|
||||
}
|
||||
|
|
@ -1554,7 +1556,7 @@ export default {
|
|||
SubjectId: this.visitInfo.SubjectId,
|
||||
SubjectVisitId: this.visitInfo.VisistId,
|
||||
TrialId: this.$route.query.trialId,
|
||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
||||
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||
}
|
||||
if (url) data.SegUrl = url;
|
||||
if (id) data.Id = id;
|
||||
|
|
@ -1574,7 +1576,7 @@ export default {
|
|||
try {
|
||||
let data = {
|
||||
SeriesId: this.series.Id,
|
||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
||||
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||
PageSize: 9999,
|
||||
PageIndex: 1,
|
||||
}
|
||||
|
|
@ -1583,6 +1585,8 @@ export default {
|
|||
this.loading = false;
|
||||
if (res.IsSuccess) {
|
||||
this.segmentList = []
|
||||
this.segmentationId = null;
|
||||
this.segmentIndex = null;
|
||||
let list = res.Result.CurrentPageData;
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let item = list[i]
|
||||
|
|
@ -1597,12 +1601,12 @@ export default {
|
|||
segments: []
|
||||
}
|
||||
this.segmentList.push(obj)
|
||||
if (item.SEGUrl) {
|
||||
await this.readSegmentation(obj)
|
||||
} else {
|
||||
await this.createSegmentation(obj.segmentationId)
|
||||
this.createSegmentationRepresentation(obj.segmentationId)
|
||||
}
|
||||
// if (item.SEGUrl) {
|
||||
// await this.readSegmentation(obj)
|
||||
// } else {
|
||||
// await this.createSegmentation(obj.segmentationId)
|
||||
// // this.createSegmentationRepresentation(obj.segmentationId)
|
||||
// }
|
||||
}
|
||||
if (!this.segmentationId) {
|
||||
this.segmentationId = obj.segmentationId
|
||||
|
|
@ -1621,45 +1625,41 @@ export default {
|
|||
bidirectional: SegmentJson.bidirectional,
|
||||
bidirectionalView: true,
|
||||
view: true,
|
||||
lock: item.locked,
|
||||
lock: true,
|
||||
id: s.Id
|
||||
}
|
||||
obj.segments.push(o)
|
||||
this.selectSegment(o, false)
|
||||
this.changeColor(s.ColorRgb, o)
|
||||
this.lockSegment(o, true)
|
||||
// this.selectSegment(o, false)
|
||||
// this.changeColor(s.ColorRgb, o)
|
||||
// this.lockSegment(o, true)
|
||||
}
|
||||
if (!this.segmentIndex) {
|
||||
this.segmentIndex = s.SegmentNumber
|
||||
}
|
||||
})
|
||||
this.$nextTick(() => {
|
||||
if (SEGMENT) {
|
||||
// console.log(SEGMENT, 'SEGMENT')
|
||||
return this.getBidirectional(obj.segments, SEGMENT)
|
||||
}
|
||||
this.getBidirectional(obj.segments, null, false)
|
||||
})
|
||||
}
|
||||
if (this.segmentationId && this.segmentIndex && this.segmentList && this.segmentList.length > 0) {
|
||||
let o = this.segmentList.find(item => item.segmentationId === this.segmentationId)
|
||||
if (o) {
|
||||
let s = o.segments.find(item => item.segmentIndex === this.segmentIndex)
|
||||
this.selectSegmentGroup(s)
|
||||
} else {
|
||||
this.segmentationId = this.segmentList[0].segmentationId
|
||||
this.segmentIndex = this.segmentationId ? this.segmentList[0].segments[0].segmentIndex : null
|
||||
if (this.segmentationId && this.segmentIndex) {
|
||||
this.selectSegmentGroup(this.segmentList[0].segments[0])
|
||||
}
|
||||
|
||||
}
|
||||
// console.log(segment, 'segment')
|
||||
|
||||
// this.selectSegment(segment)
|
||||
// this.$nextTick(() => {
|
||||
// if (SEGMENT) {
|
||||
// // console.log(SEGMENT, 'SEGMENT')
|
||||
// return this.getBidirectional(obj.segments, SEGMENT)
|
||||
// }
|
||||
// this.getBidirectional(obj.segments, null, false)
|
||||
// })
|
||||
}
|
||||
// if (this.segmentationId && this.segmentIndex && this.segmentList && this.segmentList.length > 0) {
|
||||
// let o = this.segmentList.find(item => item.segmentationId === this.segmentationId)
|
||||
// if (o) {
|
||||
// let s = o.segments.find(item => item.segmentIndex === this.segmentIndex)
|
||||
// this.selectSegmentGroup(s)
|
||||
// } else {
|
||||
// this.segmentationId = this.segmentList[0].segmentationId
|
||||
// this.segmentIndex = this.segmentationId ? this.segmentList[0].segments[0].segmentIndex : null
|
||||
// if (this.segmentationId && this.segmentIndex) {
|
||||
// this.selectSegmentGroup(this.segmentList[0].segments[0])
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
this.isloaded = false
|
||||
this.readingSegmentByConfig()
|
||||
// this.readingSegmentByConfig()
|
||||
}
|
||||
} catch (err) {
|
||||
this.loading = false
|
||||
|
|
@ -1688,7 +1688,7 @@ export default {
|
|||
SegmentName: name,
|
||||
SegmentNumber: segmentIndex,
|
||||
SegmentationId: segmentationId,
|
||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
||||
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||
SegmentJson: segmentJson
|
||||
}
|
||||
if (id) data.Id = id
|
||||
|
|
|
|||
|
|
@ -14,6 +14,25 @@
|
|||
<div v-if="imageInfo.total">Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}</div>
|
||||
<div>{{ series.Modality }}</div>
|
||||
</div>
|
||||
<div v-if="series && taskInfo && taskInfo.IsReadingTaskViewInOrder === 1" class="top-center-tool">
|
||||
<div class="toggle-visit-container">
|
||||
<div class="arrw_icon"
|
||||
:style="{ cursor: series.TaskInfo && series.TaskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: series.TaskInfo && series.TaskInfo.VisitTaskNum !== 0 ? '#fff' : '#6b6b6b' }"
|
||||
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, -1)"
|
||||
@dblclick.stop="preventDefault($event)">
|
||||
<i class="el-icon-caret-left" />
|
||||
</div>
|
||||
<div class="arrow_text">
|
||||
{{ series.TaskInfo ? series.TaskInfo.TaskBlindName : '' }}
|
||||
</div>
|
||||
<div class="arrw_icon"
|
||||
:style="{ cursor: series.TaskInfo && series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: series.TaskInfo && series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff' : '#6b6b6b' }"
|
||||
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, 1)"
|
||||
@dblclick.stop="preventDefault($event)">
|
||||
<i class="el-icon-caret-right" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="series" class="right-top-text">
|
||||
<div>{{ series.Description }}</div>
|
||||
</div>
|
||||
|
|
@ -40,10 +59,10 @@
|
|||
<div v-if="series" class="right-bottom-text">
|
||||
<div v-show="imageInfo.location">Location: {{
|
||||
`${Number(imageInfo.location).toFixed(digitPlaces)} mm`
|
||||
}}</div>
|
||||
}}</div>
|
||||
<div v-show="imageInfo.sliceThickness">Slice Thickness: {{
|
||||
`${Number(imageInfo.sliceThickness).toFixed(digitPlaces)} mm`
|
||||
}}</div>
|
||||
}}</div>
|
||||
<div v-show="imageInfo.wwwc">WW/WL: {{ imageInfo.wwwc }}</div>
|
||||
</div>
|
||||
<div class="orientation-top">
|
||||
|
|
@ -83,6 +102,19 @@ import {
|
|||
setPetTransferFunctionForVolumeActor
|
||||
} from './helpers/index.js'
|
||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||
import {
|
||||
renderSegmentation,
|
||||
readingSegmentByConfig,
|
||||
selectSegmentation,
|
||||
selectSegment,
|
||||
createSegmentationRepresentation,
|
||||
viewSegmentation,
|
||||
viewSegment,
|
||||
jumpBidirectional,
|
||||
viewBidirectional,
|
||||
changeColor,
|
||||
resetViewport
|
||||
} from "./helpers/segmentations"
|
||||
export default {
|
||||
name: 'MPRViewport',
|
||||
props: {
|
||||
|
|
@ -101,6 +133,32 @@ export default {
|
|||
histogramVisible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
actionConfiguration: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
SegmentConfig: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
curSegSeries: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
segmentIndex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
segmentationId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
@ -154,6 +212,39 @@ export default {
|
|||
this.$nextTick(() => {
|
||||
this.initViewport()
|
||||
})
|
||||
DicomEvent.$on('createSegmentationRepresentation', (segmentationId) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
createSegmentationRepresentation(this.viewportId, segmentationId)
|
||||
})
|
||||
DicomEvent.$on('viewSegmentation', (obj) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
viewSegmentation(obj, this.viewportId)
|
||||
})
|
||||
DicomEvent.$on('viewSegment', (obj) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
viewSegment(obj, this.viewportId)
|
||||
})
|
||||
DicomEvent.$on('jumpBidirectional', (obj) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
jumpBidirectional(obj, this.viewportId, this.volumeId)
|
||||
})
|
||||
DicomEvent.$on('viewBidirectional', (obj) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
viewBidirectional(obj, this.viewportId)
|
||||
})
|
||||
DicomEvent.$on('changeColor', (obj) => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
changeColor(obj, this.viewportId)
|
||||
})
|
||||
DicomEvent.$on('resetViewport', () => {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
resetViewport(this.viewportId)
|
||||
})
|
||||
DicomEvent.$on('renderSegmentation', async (viewportId) => {
|
||||
// if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
if (this.viewportId !== viewportId) return false
|
||||
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.segmentationId, this.segmentIndex, this.renderingEngineId, null, this.actionConfiguration)
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
MPRInfo: {
|
||||
|
|
@ -172,6 +263,25 @@ export default {
|
|||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
SegmentConfig: {
|
||||
handler() {
|
||||
if (!this.segmentationId) return false
|
||||
if (!this.series.TaskInfo) return false
|
||||
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
segmentIndex() {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
if (this.segmentIndex <= 0) return false
|
||||
selectSegment(this.viewportId, this.segmentationId, this.segmentIndex)
|
||||
},
|
||||
segmentationId() {
|
||||
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||
if (!this.segmentationId) return false
|
||||
selectSegmentation(this.viewportId, this.segmentationId)
|
||||
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -549,13 +659,9 @@ export default {
|
|||
console.log("渲染成功")
|
||||
}
|
||||
}]).then(r => {
|
||||
if (data.segment) {
|
||||
return DicomEvent.$emit("isloaded", { segment: data.segment, isChange: data.isChange })
|
||||
}
|
||||
if (data.isLocation) {
|
||||
setTimeout(() => { csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); })
|
||||
}
|
||||
DicomEvent.$emit("isloaded", { isChange: data.isChange })
|
||||
})
|
||||
viewport.render()
|
||||
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
|
||||
|
|
@ -567,11 +673,10 @@ export default {
|
|||
renderingEngine.render()
|
||||
}, 100)
|
||||
}
|
||||
|
||||
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.segmentationId, this.segmentIndex, this.renderingEngineId, data.segment, this.actionConfiguration)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
},
|
||||
cornerstoneToolsMouseMove(e) {
|
||||
const { currentPoints } = e.detail
|
||||
|
|
|
|||
|
|
@ -0,0 +1,430 @@
|
|||
import * as cornerstoneTools from '@cornerstonejs/tools';
|
||||
import * as cornerstone from "@cornerstonejs/core";
|
||||
import dcmjs from '@/utils/dcmUpload/dcmjs'
|
||||
import * as cornerstoneAdapters from "@cornerstonejs/adapters";
|
||||
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
|
||||
import * as polySeg from '@cornerstonejs/polymorphic-segmentation'
|
||||
cornerstoneTools.init({ addons: { polySeg } })
|
||||
import { getSegmentationList, getSegmentList } from '@/api/reading'
|
||||
import Vue from 'vue'
|
||||
const {
|
||||
ToolGroupManager,
|
||||
Enums: csToolsEnums,
|
||||
segmentation,
|
||||
annotation,
|
||||
LabelMapEditWithContourTool,
|
||||
SegmentBidirectionalTool,
|
||||
CrosshairsTool,
|
||||
utilities: CStUtils,
|
||||
} = cornerstoneTools;
|
||||
const { MouseBindings, Events: toolsEvents } = csToolsEnums
|
||||
const { segmentation: segmentationUtils } = CStUtils;
|
||||
const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone;
|
||||
const { Cornerstone3D } = cornerstoneAdapters.adaptersSEG;
|
||||
let viewportInfo = {}
|
||||
let renderingEngineId = null
|
||||
async function createSegmentation(toolGroupId, volumeId, segmentationId) {
|
||||
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) || ToolGroupManager.getToolGroup('share-viewport-volume')
|
||||
toolGroup.setToolActive(
|
||||
LabelMapEditWithContourTool.toolName,
|
||||
);
|
||||
if (!cache.getVolume(segmentationId)) {
|
||||
await volumeLoader.createAndCacheDerivedLabelmapVolume(
|
||||
volumeId,
|
||||
{
|
||||
volumeId: segmentationId
|
||||
}
|
||||
)
|
||||
}
|
||||
if (!segmentation.state.getSegmentation(segmentationId)) {
|
||||
segmentation.addSegmentations([
|
||||
{
|
||||
segmentationId,
|
||||
representation: {
|
||||
type: cornerstoneTools.Enums.SegmentationRepresentations
|
||||
.Labelmap,
|
||||
data: {
|
||||
volumeId: segmentationId
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
async function createSegmentationRepresentation(viewportId, segmentationId) {
|
||||
segmentation.addSegmentationRepresentations(viewportId, [
|
||||
{
|
||||
segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||
},
|
||||
])
|
||||
}
|
||||
async function readSegmentation(obj, series, segmentationId, isFile = false) {
|
||||
let imageId = null
|
||||
if (isFile) {
|
||||
imageId = cornerstoneDICOMImageLoader.wadouri.fileManager.add(obj);
|
||||
} else {
|
||||
const imageIdObj = await cornerstoneDICOMImageLoader.wadouri.loadImage(`wadouri:${Vue.prototype.OSSclientConfig.basePath}${obj}`).promise
|
||||
imageId = imageIdObj.imageId
|
||||
}
|
||||
const image = await imageLoader.loadAndCacheImage(imageId);
|
||||
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
const instance = metaData.get("instance", imageId);
|
||||
|
||||
if (instance.Modality !== "SEG") {
|
||||
console.error("This is not segmentation: " + file.name);
|
||||
return;
|
||||
}
|
||||
|
||||
const arrayBuffer = image.data.byteArray.buffer;
|
||||
await loadSegmentation(arrayBuffer, series, segmentationId);
|
||||
}
|
||||
async function loadSegmentation(arrayBuffer, series, segmentationId) {
|
||||
const generateToolState =
|
||||
await Cornerstone3D.Segmentation.generateToolState(
|
||||
series.ImageIds,
|
||||
arrayBuffer,
|
||||
metaData,
|
||||
);
|
||||
if (generateToolState.labelmapBufferArray.length !== 1) {
|
||||
alert(
|
||||
"Overlapping segments in your segmentation are not supported yet. You can turn on the skipOverlapping option but it will override the overlapping segments."
|
||||
);
|
||||
return;
|
||||
}
|
||||
// await createSegmentation(segmentationId);
|
||||
let arr = []
|
||||
generateToolState.segMetadata.data.forEach(item => {
|
||||
if (item) {
|
||||
let Target = JSON.parse(JSON.stringify(item))
|
||||
arr.push(Target)
|
||||
}
|
||||
})
|
||||
|
||||
let mapping = {}
|
||||
|
||||
arr.forEach((item, index) => {
|
||||
mapping[index + 1] = Number(item.SegmentNumber)
|
||||
})
|
||||
const megmentGroup =
|
||||
segmentation.state.getSegmentation(segmentationId);
|
||||
const { imageIds } = megmentGroup.representationData.Labelmap;
|
||||
const derivedSegmentationImages = imageIds.map(imageId =>
|
||||
cache.getImage(imageId)
|
||||
);
|
||||
|
||||
const volumeScalarData = new Uint8Array(
|
||||
generateToolState.labelmapBufferArray[0]
|
||||
);
|
||||
const remappedData = new Uint8Array(volumeScalarData.length);
|
||||
for (let i = 0; i < volumeScalarData.length; i++) {
|
||||
const value = volumeScalarData[i];
|
||||
remappedData[i] = value === 0 ? 0 : (mapping[value] ? mapping[value] : value);
|
||||
}
|
||||
for (let i = 0; i < derivedSegmentationImages.length; i++) {
|
||||
const voxelManager = derivedSegmentationImages[i].voxelManager;
|
||||
const scalarData = voxelManager.getScalarData();
|
||||
scalarData.set(
|
||||
remappedData.slice(
|
||||
i * scalarData.length,
|
||||
(i + 1) * scalarData.length
|
||||
)
|
||||
);
|
||||
voxelManager.setScalarData(scalarData);
|
||||
}
|
||||
}
|
||||
function hex2Rgb(hexValue, alpha = 1) {
|
||||
const rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||
const hex = hexValue.replace(rgx, (m, r, g, b) => r + r + g + g + b + b);
|
||||
const rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
if (!rgb) {
|
||||
return hexValue;
|
||||
}
|
||||
const r = parseInt(rgb[1], 16),
|
||||
g = parseInt(rgb[2], 16),
|
||||
b = parseInt(rgb[3], 16);
|
||||
return [r, g, b, alpha * 255];
|
||||
}
|
||||
function removeSegmentFromViewport(viewportId) {
|
||||
return new Promise(resolve => {
|
||||
if (viewportInfo[viewportId] && viewportInfo[viewportId].length > 0) {
|
||||
viewportInfo[viewportId].forEach(async segmentationId => {
|
||||
segmentation.removeSegmentation(segmentationId)
|
||||
segmentation.state.removeSegmentation(segmentationId)
|
||||
let annotations = annotation.state.getAllAnnotations().filter(item => item.metadata.segmentationId && segmentationId === item.metadata.segmentationId && item.metadata.segmentIndex && item.metadata.toolName === "SegmentBidirectional");
|
||||
annotations.forEach(item => {
|
||||
annotation.state.removeAnnotation(item.annotationUID)
|
||||
})
|
||||
})
|
||||
}
|
||||
viewportInfo[viewportId] = []
|
||||
resolve(true)
|
||||
})
|
||||
}
|
||||
function createSegmentConfiguration(segmentIndex, segmentationId, viewportId, actionConfiguration, otherSegments) {
|
||||
const containedSegmentIndices = otherSegments
|
||||
? { has: (segmentIndex) => otherSegments.indexOf(segmentIndex) !== -1 }
|
||||
: undefined;
|
||||
const colorConfig = segmentation.config.color.getSegmentIndexColor(
|
||||
viewportId,
|
||||
segmentationId,
|
||||
segmentIndex
|
||||
);
|
||||
// Allow null style to skip style set
|
||||
let color, activeColor;
|
||||
if (colorConfig?.length) {
|
||||
color = `rgb(${colorConfig.join(',')})`;
|
||||
activeColor = color;
|
||||
}
|
||||
const style = {
|
||||
color,
|
||||
colorHighlightedActive: activeColor,
|
||||
colorActive: activeColor,
|
||||
textBoxColor: color,
|
||||
textBoxColorActive: activeColor,
|
||||
textBoxColorHighlightedActive: activeColor,
|
||||
};
|
||||
const label = otherSegments
|
||||
? `Combined ${segmentIndex} with ${otherSegments.join(', ')}`
|
||||
: `Segment ${segmentIndex}`;
|
||||
|
||||
actionConfiguration.contourBidirectional.data.segmentData.set(segmentIndex, {
|
||||
containedSegmentIndices,
|
||||
label,
|
||||
style,
|
||||
});
|
||||
actionConfiguration.contourBidirectional.data.segmentationId = segmentationId
|
||||
actionConfiguration.contourBidirectional.data.segmentIndex = segmentIndex
|
||||
}
|
||||
async function readingSegmentByConfig(series, visitInfo, viewportId, segmentationId, SegmentConfig) {
|
||||
let data = {
|
||||
SeriesId: series.Id,
|
||||
VisitTaskId: visitInfo.VisitTaskId,
|
||||
PageSize: 9999,
|
||||
PageIndex: 1,
|
||||
}
|
||||
let res = await getSegmentationList(data);
|
||||
if (res.IsSuccess) {
|
||||
let list = res.Result.CurrentPageData;
|
||||
changeInactiveSegmentShow(list, viewportId, segmentationId, SegmentConfig)
|
||||
}
|
||||
segmentation.config.style.setStyle(
|
||||
{
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||
},
|
||||
{
|
||||
renderFill: SegmentConfig.renderFill,
|
||||
renderOutline: SegmentConfig.renderOutline,
|
||||
outlineWidth: Number(SegmentConfig.outlineWidth),
|
||||
fillAlpha: Number(SegmentConfig.fillAlpha),
|
||||
}
|
||||
)
|
||||
}
|
||||
function selectSegmentation(viewportId, segmentationId) {
|
||||
segmentation.activeSegmentation.setActiveSegmentation(viewportId, segmentationId)
|
||||
}
|
||||
function selectSegment(viewportId, segmentationId, segmentIndex) {
|
||||
selectSegmentation(viewportId, segmentationId)
|
||||
segmentation.segmentIndex.setActiveSegmentIndex(segmentationId, segmentIndex);
|
||||
}
|
||||
async function changeInactiveSegmentShow(list, viewportId, segmentationId, SegmentConfig) {
|
||||
let segmentList = list
|
||||
segmentList.forEach(segment => {
|
||||
segmentation.config.visibility.setSegmentationRepresentationVisibility(
|
||||
viewportId,
|
||||
{
|
||||
segmentationId: segment.Id,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||
},
|
||||
SegmentConfig.InactiveSegmentations.show
|
||||
);
|
||||
})
|
||||
segmentation.config.visibility.setSegmentationRepresentationVisibility(
|
||||
viewportId,
|
||||
{
|
||||
segmentationId: segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||
},
|
||||
true
|
||||
);
|
||||
let arr = []
|
||||
for (let i = 0; i < segmentList.length; i++) {
|
||||
let item = segmentList[i]
|
||||
let params = {
|
||||
SegmentationId: item.Id,
|
||||
PageSize: 9999,
|
||||
PageIndex: 1,
|
||||
}
|
||||
let r = await getSegmentList(params)
|
||||
if (r.IsSuccess) {
|
||||
let segments = r.Result.CurrentPageData
|
||||
segments.forEach(s => {
|
||||
let obj = {
|
||||
segmentationId: item.Id,
|
||||
segmentIndex: s.SegmentNumber,
|
||||
view: SegmentConfig.InactiveSegmentations.show
|
||||
}
|
||||
if (item.Id === segmentationId) {
|
||||
obj.view = true
|
||||
}
|
||||
arr.push(obj)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
viewBidirectional(arr, viewportId)
|
||||
}
|
||||
function viewSegmentation(item, viewportId) {
|
||||
segmentation.config.visibility.setSegmentationRepresentationVisibility(
|
||||
viewportId,
|
||||
{
|
||||
segmentationId: item.segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||
},
|
||||
item.view
|
||||
);
|
||||
viewBidirectional(item.segments, viewportId)
|
||||
}
|
||||
async function jumpBidirectional(item, viewportId, volumeId) {
|
||||
// DicomEvent.$emit('jumpBidirectional', item)
|
||||
if (item.bidirectional) {
|
||||
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||
console.log(an, 'an')
|
||||
if (!an) return false
|
||||
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||
const viewport = renderingEngine.getViewport(viewportId)
|
||||
let key = Object.keys(an.data.cachedStats)[0]; // referencedImageId
|
||||
if (key) {
|
||||
let sliceIndex = key.split("?")[1].split("&")[0].split("=")[1]
|
||||
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIndex });
|
||||
} else {
|
||||
const points = an.data.handles.points;
|
||||
const worldPoint = points[0]; // 取一个点
|
||||
let volume = cache.getVolume(volumeId)
|
||||
let { imageData, numFrames } = volume
|
||||
const ijk = imageData.worldToIndex(worldPoint);
|
||||
const sliceIndex = Math.abs(Math.round(ijk[2]));
|
||||
// console.log(sliceIndex, 'sliceIndex')
|
||||
csUtils.jumpToSlice(viewport.element, { imageIndex: numFrames - sliceIndex - 1 });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
function viewSegment(item, viewportId) {
|
||||
segmentation.config.visibility.setSegmentIndexVisibility(viewportId, {
|
||||
segmentationId: item.segmentationId,
|
||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||
}, item.segmentIndex, item.view)
|
||||
viewBidirectional([item], viewportId)
|
||||
}
|
||||
function viewBidirectional(arr, viewportId) {
|
||||
for (let j = 0; j < arr.length; j++) {
|
||||
let item = arr[j]
|
||||
let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||
// item.bidirectionalView = view
|
||||
if (!bidirectional) continue
|
||||
annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, item.view)
|
||||
}
|
||||
resetViewport(viewportId)
|
||||
}
|
||||
function resetViewport(viewportId) {
|
||||
let renderingEngine = getRenderingEngine(renderingEngineId)
|
||||
const viewport = renderingEngine.getViewport(viewportId)
|
||||
viewport.render()
|
||||
}
|
||||
function changeColor(item, viewportId) {
|
||||
segmentation.config.color.setSegmentIndexColor(viewportId, item.segmentationId, item.segmentIndex, hex2Rgb(item.color))
|
||||
}
|
||||
async function renderSegmentation(series, visitInfo, viewportId, SegmentConfig, segmentationId, segmentIndex, RenderingEngineId, Segment = null, actionConfiguration) {
|
||||
try {
|
||||
// console.log(segmentation, 'segmentation')
|
||||
renderingEngineId = RenderingEngineId
|
||||
await removeSegmentFromViewport(viewportId)
|
||||
let data = {
|
||||
SeriesId: series.Id,
|
||||
VisitTaskId: visitInfo.VisitTaskId,
|
||||
PageSize: 9999,
|
||||
PageIndex: 1,
|
||||
}
|
||||
let res = await getSegmentationList(data);
|
||||
if (res.IsSuccess) {
|
||||
let list = res.Result.CurrentPageData;
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let item = list[i]
|
||||
|
||||
await createSegmentation(viewportId, series.SeriesInstanceUid, item.Id)
|
||||
if (item.SEGUrl) await readSegmentation(item.SEGUrl, series, item.Id)
|
||||
createSegmentationRepresentation(viewportId, item.Id)
|
||||
if (!viewportInfo[viewportId]) {
|
||||
viewportInfo[viewportId] = [item.Id]
|
||||
} else {
|
||||
viewportInfo[viewportId].push(item.Id)
|
||||
}
|
||||
let params = {
|
||||
SegmentationId: item.Id,
|
||||
PageSize: 9999,
|
||||
PageIndex: 1,
|
||||
}
|
||||
let r = await getSegmentList(params)
|
||||
if (r.IsSuccess) {
|
||||
let segments = r.Result.CurrentPageData
|
||||
segments.forEach(s => {
|
||||
let SegmentJson = s.SegmentJson ? JSON.parse(s.SegmentJson) : {};
|
||||
segmentation.segmentIndex.setActiveSegmentIndex(s.SegmentationId, s.SegmentNumber);
|
||||
segmentation.config.color.setSegmentIndexColor(viewportId, s.SegmentationId, s.SegmentNumber, hex2Rgb(s.ColorRgb))
|
||||
segmentation.segmentLocking.setSegmentIndexLocked(s.SegmentationId, s.SegmentNumber, true)
|
||||
if (SegmentJson.bidirectional) {
|
||||
let { majorAxis, minorAxis } = SegmentJson.bidirectional
|
||||
// createSegmentConfiguration(s.SegmentNumber, s.SegmentationId, viewportId, actionConfiguration)
|
||||
SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], {
|
||||
segmentIndex: s.SegmentNumber,
|
||||
segmentationId: s.SegmentationId,
|
||||
})
|
||||
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === s.SegmentationId && i.metadata.segmentIndex === SegmentJson.bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||
if (an) {
|
||||
annotation.locking.setAnnotationLocked(an.annotationUID, true)
|
||||
annotation.visibility.setAnnotationVisibility(an.annotationUID, item.bidirectionalView)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// this.$nextTick(() => {
|
||||
// if (SEGMENT) {
|
||||
// // console.log(SEGMENT, 'SEGMENT')
|
||||
// return this.getBidirectional(obj.segments, SEGMENT)
|
||||
// }
|
||||
// this.getBidirectional(obj.segments, null, false)
|
||||
// })
|
||||
selectSegment(viewportId, segmentationId, segmentIndex)
|
||||
if (Segment) {
|
||||
jumpBidirectional(Segment, viewportId, series.SeriesInstanceUid)
|
||||
}
|
||||
}
|
||||
}
|
||||
readingSegmentByConfig(series, visitInfo, viewportId, segmentationId, SegmentConfig)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
createSegmentation,
|
||||
createSegmentationRepresentation,
|
||||
readSegmentation,
|
||||
renderSegmentation,
|
||||
readingSegmentByConfig,
|
||||
selectSegment,
|
||||
selectSegmentation,
|
||||
viewSegmentation,
|
||||
viewSegment,
|
||||
jumpBidirectional,
|
||||
viewBidirectional,
|
||||
changeColor,
|
||||
resetViewport
|
||||
}
|
||||
Loading…
Reference in New Issue