分割标记渲染结构变更

uat_us
wangxiaoshuang 2026-04-14 16:19:36 +08:00
parent 5a7fa1fb77
commit 312ab754e1
6 changed files with 1221 additions and 500 deletions

View File

@ -16,6 +16,7 @@
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "3.726.1", "@aws-sdk/client-s3": "3.726.1",
"@cornerstonejs/adapters": "^4.19.2", "@cornerstonejs/adapters": "^4.19.2",
"@cornerstonejs/polymorphic-segmentation": "4.19.2",
"@cornerstonejs/calculate-suv": "^1.1.0", "@cornerstonejs/calculate-suv": "^1.1.0",
"@cornerstonejs/core": "^4.19.2", "@cornerstonejs/core": "^4.19.2",
"@cornerstonejs/dicom-image-loader": "^4.19.2", "@cornerstonejs/dicom-image-loader": "^4.19.2",

View File

@ -81,6 +81,19 @@ import {
} from './helpers/index.js' } from './helpers/index.js'
import { vec3, mat4 } from 'gl-matrix' import { vec3, mat4 } from 'gl-matrix'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent' 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 { export default {
name: 'MPRViewport', name: 'MPRViewport',
props: { props: {
@ -105,6 +118,32 @@ export default {
histogramVisible: { histogramVisible: {
type: Boolean, type: Boolean,
default: false 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() { data() {
@ -155,6 +194,39 @@ export default {
this.$nextTick(() => { this.$nextTick(() => {
this.initViewport() 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: { watch: {
MPRInfo: { MPRInfo: {
@ -173,6 +245,25 @@ export default {
} }
}, },
deep: true 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: { methods: {
@ -505,7 +596,6 @@ export default {
setCtTransferFunctionForVolumeActor(r) setCtTransferFunctionForVolumeActor(r)
} }
console.log("渲染成功") console.log("渲染成功")
DicomEvent.$emit("isloaded", { isChange: false })
} }
}]).then(r => { }]).then(r => {
if (data.isLocation || !this.imageInfo.zoom) { if (data.isLocation || !this.imageInfo.zoom) {
@ -522,6 +612,7 @@ export default {
renderingEngine.render() renderingEngine.render()
}, 100) }, 100)
} }
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.segmentationId, this.segmentIndex, this.renderingEngineId, null, this.actionConfiguration)
} catch (e) { } catch (e) {
console.log(e) console.log(e)
} }

View File

@ -313,7 +313,9 @@
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)"> @dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
<VolumeViewport :ref="`viewport-${index}`" :data-viewport-uid="`viewport-${index}`" <VolumeViewport :ref="`viewport-${index}`" :data-viewport-uid="`viewport-${index}`"
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-${index}`" :viewport-index="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" @toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" @renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup"
@resetViewport="resetViewport" v-if="readingTool === 3" @resetViewport="resetViewport" v-if="readingTool === 3"
@ -333,7 +335,10 @@
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)"> @dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
<MPRViewport :ref="`viewport-MPR-${index}`" :data-viewport-uid="`viewport-MPR-${index}`" <MPRViewport :ref="`viewport-MPR-${index}`" :data-viewport-uid="`viewport-MPR-${index}`"
:rendering-engine-id="renderingEngineId" :viewport-id="`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" @toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" @renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup"
v-resize="(e) => handleSizeChange(e, `viewport-MPR-${index}`)" /> v-resize="(e) => handleSizeChange(e, `viewport-MPR-${index}`)" />
@ -362,9 +367,11 @@
<Segmentations ref="Segmentations" :visitInfo="taskInfo" :isMPR="isMPR" <Segmentations ref="Segmentations" :visitInfo="taskInfo" :isMPR="isMPR"
:volumeToolGroupId="volumeToolGroupId" :viewportKey="viewportKey" :global-loading.sync="loading" :volumeToolGroupId="volumeToolGroupId" :viewportKey="viewportKey" :global-loading.sync="loading"
:loadingText.sync="loadingText" :rendering-engine-id="renderingEngineId" :loadingText.sync="loadingText" :rendering-engine-id="renderingEngineId"
:activeViewportIndex="activeViewportIndex" :activeTool.sync="activeTool" :SegmentConfig="SegmentConfig" :segId.sync="segId" :segIndex.sync="segIndex"
:actionConfiguration="actionConfiguration" :histogramVisible="histogramVisible" :curSegSeries.sync="curSegSeries" :activeViewportIndex="activeViewportIndex"
@setToolsPassive="setToolsPassive" @resetQuestion="resetQuestion" /> :activeTool.sync="activeTool" :actionConfiguration="actionConfiguration"
:histogramVisible="histogramVisible" @setToolsPassive="setToolsPassive"
@resetQuestion="resetQuestion" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('trials:reading:dicom3D:tabs:ecrf')" name="ecrf"> <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" <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" <histogram ref="histogram" v-if="readingTool === 3" :visible.sync="histogramVisible" :activeTool.sync="activeTool"
:viewportKey="viewportKey" :rendering-engine-id="renderingEngineId" :activeViewportIndex="activeViewportIndex" /> :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" <upload-dicom-and-nonedicom v-if="uploadImageVisible" :subject-id="uploadSubjectId"
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible" :subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible"
:visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" /> :visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" />
@ -516,6 +528,7 @@ import {
RenderingEngine, RenderingEngine,
Enums, Enums,
// imageLoader, // imageLoader,
// CONSTANTS,
metaData, metaData,
volumeLoader, volumeLoader,
getRenderingEngine, getRenderingEngine,
@ -537,6 +550,8 @@ import MPRViewport from './MPRViewport'
import VolumeViewport from './VolumeViewport' import VolumeViewport from './VolumeViewport'
import Segmentations from './Segmentations' import Segmentations from './Segmentations'
import histogram from "./histogram" import histogram from "./histogram"
// import SurfaceViewport from "./SurfaceViewport"
// import ContourViewport from "./ContourViewport"
import mRecisit from './mRecist/QuestionList' import mRecisit from './mRecist/QuestionList'
import recisit from './Recist/QuestionList' import recisit from './Recist/QuestionList'
import customizeQuestionList from './customize/QuestionList' import customizeQuestionList from './customize/QuestionList'
@ -567,6 +582,9 @@ const {
ToolGroupManager, ToolGroupManager,
Enums: csToolsEnums, Enums: csToolsEnums,
StackScrollTool, StackScrollTool,
TrackballRotateTool,
PlanarFreehandContourSegmentationTool,
SplineContourSegmentationTool,
// ScaleOverlayTool, // ScaleOverlayTool,
PanTool, PanTool,
ZoomTool, ZoomTool,
@ -629,6 +647,8 @@ export default {
VolumeViewport, VolumeViewport,
Segmentations, Segmentations,
histogram, histogram,
// SurfaceViewport,
// ContourViewport,
mRecisit, mRecisit,
recisit, recisit,
customizeQuestionList, customizeQuestionList,
@ -662,7 +682,7 @@ export default {
activeTaskIndex: -1, activeTaskIndex: -1,
activeStudyIndex: -1, activeStudyIndex: -1,
activeSeriesIndex: -1, activeSeriesIndex: -1,
currentVisitInfo: null, currentVisitInfo: {},
layout: 1, layout: 1,
cellsMax: 4, cellsMax: 4,
rows: 1, 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, fusionOverlayModality: null,
lastUpper: null, lastUpper: null,
hasFusionUpperInitialized: false, hasFusionUpperInitialized: false,
timer: null, timer: {},
FullTimerOut: null, FullTimerOut: null,
isDelay: false, isDelay: false,
histogramVisible: false histogramVisible: false,
// surfaceVisible: false
} }
}, },
computed: { computed: {
@ -951,6 +985,11 @@ export default {
this.getSystemInfoReading(); this.getSystemInfoReading();
}, },
methods: { methods: {
showSurface(obj) {
// this.surfaceVisible = true
// this.$refs.contourViewport.setSeriesInfo(obj)
// this.$refs.surfaceViewport.setSeriesInfo(obj)
},
async openHistogram() { async openHistogram() {
this.histogramVisible = true this.histogramVisible = true
this.setToolsPassive() this.setToolsPassive()
@ -958,8 +997,8 @@ export default {
}, },
handleSizeChange(e, viewportId) { handleSizeChange(e, viewportId) {
// console.log('handleSizeChange', e) let index = this.$refs[viewportId][0].series.SliceIndex
this.resetRenderingEngine(viewportId) this.resetRenderingEngine(viewportId, index)
}, },
resetQuestion() { resetQuestion() {
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].getQuestions(false) 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) { if ((this.criterionType === 0 && this.readingTool === 0) || this.readingTool === 3) {
const volumeElement1 = this.$refs['viewport-MPR-0'][0].$el const volumeElement1 = this.$refs['viewport-MPR-0'][0].$el
@ -1377,6 +1437,7 @@ export default {
} }
renderingEngine.setViewports(viewportInputArray) renderingEngine.setViewports(viewportInputArray)
this.addAnnotationListeners() this.addAnnotationListeners()
// cornerstoneTools.addTool(TrackballRotateTool)
cornerstoneTools.addTool(StackScrollTool) cornerstoneTools.addTool(StackScrollTool)
cornerstoneTools.addTool(PanTool) cornerstoneTools.addTool(PanTool)
cornerstoneTools.addTool(ZoomTool) cornerstoneTools.addTool(ZoomTool)
@ -1401,6 +1462,8 @@ export default {
cornerstoneTools.addTool(LabelMapEditWithContourTool) cornerstoneTools.addTool(LabelMapEditWithContourTool)
cornerstoneTools.addTool(BrushTool) cornerstoneTools.addTool(BrushTool)
cornerstoneTools.addTool(SegmentBidirectionalTool) cornerstoneTools.addTool(SegmentBidirectionalTool)
// cornerstoneTools.addTool(PlanarFreehandContourSegmentationTool);
// cornerstoneTools.addTool(SplineContourSegmentationTool);
viewportIds.forEach((viewportId, i) => { viewportIds.forEach((viewportId, i) => {
// const toolGroupId = `viewport-${i}` // const toolGroupId = `viewport-${i}`
let toolGroupId = viewportId let toolGroupId = viewportId
@ -1410,9 +1473,32 @@ export default {
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) ? ToolGroupManager.getToolGroup(toolGroupId) : ToolGroupManager.createToolGroup(toolGroupId) const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) ? ToolGroupManager.getToolGroup(toolGroupId) : ToolGroupManager.createToolGroup(toolGroupId)
toolGroup.addViewport(viewportId, renderingEngineId) toolGroup.addViewport(viewportId, renderingEngineId)
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, { toolGroup.addTool(StackScrollTool.toolName, {
loop: true, // loop: true, //
}) })
toolGroup.addTool(ScaleOverlayTool.toolName) toolGroup.addTool(ScaleOverlayTool.toolName)
toolGroup.addTool(PanTool.toolName) toolGroup.addTool(PanTool.toolName)
@ -1551,6 +1637,7 @@ export default {
] ]
}) })
} }
toolGroup.setToolConfiguration( toolGroup.setToolConfiguration(
ScaleOverlayTool.toolName, ScaleOverlayTool.toolName,
{ {
@ -1600,6 +1687,8 @@ export default {
if (this.readingTool === 3) toolGroup.setToolEnabled(LabelMapEditWithContourTool.toolName) if (this.readingTool === 3) toolGroup.setToolEnabled(LabelMapEditWithContourTool.toolName)
} }
toolGroup.setToolPassive(EraserTool.toolName) toolGroup.setToolPassive(EraserTool.toolName)
}
}) })
eventTarget.addEventListener('cornerstoneimageloadprogress', this.imageLoadProgress) eventTarget.addEventListener('cornerstoneimageloadprogress', this.imageLoadProgress)
// console.log(Events, toolsEvents) // console.log(Events, toolsEvents)
@ -2627,7 +2716,7 @@ export default {
viewport.render() viewport.render()
renderingEngine.render() renderingEngine.render()
if (this.readingTool === 3) { 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) this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resize(forceFitToWindow)
}, },
// //
resetRenderingEngine(viewportId = null) { resetRenderingEngine(viewportId = null, i) {
if (this.timer) { if (this.timer[viewportId]) {
clearInterval(this.timer) clearInterval(this.timer[viewportId])
this.timer = null this.timer[viewportId] = null
} }
const renderingEngine = getRenderingEngine(renderingEngineId) const renderingEngine = getRenderingEngine(renderingEngineId)
const viewport = renderingEngine.getViewport(viewportId) const viewport = renderingEngine.getViewport(viewportId)
if (!viewport) return false if (!viewport) return false
if (viewport.volumeIds.size <= 0) return false if (viewport.volumeIds.size <= 0) return false
let index = null let index = null
this.timer = setTimeout(() => { this.timer[viewportId] = setTimeout(() => {
index = index || index === 0 ? index : this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].series.SliceIndex index = i || i === 0 ? i : this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].series.SliceIndex
renderingEngine.resize(true, false) renderingEngine.resize(true, false)
renderingEngine.render() renderingEngine.render()
this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].setFullScreen(index) this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].setFullScreen(index)
clearTimeout(this.timer) clearTimeout(this.timer[viewportId])
this.timer = null this.timer[viewportId] = null
if (this.readingTool === 3) { if (this.readingTool === 3) {
DicomEvent.$emit('isloaded', { isChange: false }) DicomEvent.$emit('isloaded', { isChange: false, viewportId })
} }
}, 100) }, 100)
}, },
@ -2946,7 +3035,7 @@ export default {
if (this.readingTool === 3 || this.isMPR) { if (this.readingTool === 3 || this.isMPR) {
// this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series) // this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series)
this.$nextTick(() => { this.$nextTick(() => {
this.resetRenderingEngine() // this.resetRenderingEngine(`${this.viewportKey}-${index}`)
this.isDelay = true this.isDelay = true
this.setDelay(2000) this.setDelay(2000)
// if (this.readingTool === 3) { // if (this.readingTool === 3) {
@ -4048,8 +4137,13 @@ export default {
this.saveCustomAnnotationTimer = null this.saveCustomAnnotationTimer = null
} }
if (this.timer) { if (this.timer) {
clearInterval(this.timer) Object.keys(this.timer).forEach(key => {
this.timer = null if (this.timer[key]) {
clearInterval(this.timer[key])
this.timer[key] = null
}
})
this.timer = {}
} }
if (this.FullTimerOut) { if (this.FullTimerOut) {
clearTimeout(this.FullTimerOut) clearTimeout(this.FullTimerOut)

View File

@ -80,7 +80,8 @@
@click.stop="changeShowSegmentConfig" /> @click.stop="changeShowSegmentConfig" />
</div> </div>
</template> </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> <span><i class="el-icon-plus"></i>
{{ $t('trials:reading:Segmentations:button:addSegmention') }} {{ $t('trials:reading:Segmentations:button:addSegmention') }}
</span> </span>
@ -124,16 +125,11 @@
$t('trials:reading:Segmentations:title:InactiveSegmentationsShow') $t('trials:reading:Segmentations:title:InactiveSegmentationsShow')
}}</span> }}</span>
</div> </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> </div>
<template v-if="segmentList.length > 0"> <template v-if="segmentList.length > 0">
<div class="SegmentGroupBox"> <div class="SegmentGroupBox">
<div style="display: flex;align-items: center;"> <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="SegmentGroupBtnBox">
<div class="SegmentGroupBtn" @click.stop="addSegmentGroup"> <div class="SegmentGroupBtn" @click.stop="addSegmentGroup">
{{ $t('trials:reading:Segmentations:button:addSegmentGroup') }} {{ $t('trials:reading:Segmentations:button:addSegmentGroup') }}
@ -156,7 +152,7 @@
</el-option> </el-option>
</el-select> </el-select>
</div> </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;" <i class="el-icon-warning-outline" style="color:red;margin-right: 5px;"
:title="$t('trials:reading:Segmentations:tip:segmentationIsNotSave')" :title="$t('trials:reading:Segmentations:tip:segmentationIsNotSave')"
v-if="!curSegmentGroup.isSaved"></i> v-if="!curSegmentGroup.isSaved"></i>
@ -167,7 +163,8 @@
</div> </div>
</div> </div>
<div class="addSegmentBox" @click.stop="addSegment" <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> <span><i class="el-icon-plus"></i>
{{ $t('trials:reading:Segmentations:button:addSegment') }} {{ $t('trials:reading:Segmentations:button:addSegment') }}
</span> </span>
@ -220,7 +217,7 @@
<i class="el-icon-lock" v-if="item.lock" @click.stop="lockSegment(item, false)"></i> <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" <el-popover placement="bottom" width="40" trigger="click" class="docShow"
:value="popoverId === `popover-${item.segmentationId}_${item.segmentIndex}`" :value="popoverId === `popover-${item.segmentationId}_${item.segmentIndex}`"
@show="handleClickPopover(item)"> @show="handleClickPopover(item)" v-if="readingTaskState < 2">
<div class="SegmentGroupBtnBox"> <div class="SegmentGroupBtnBox">
<div class="SegmentGroupBtn" @click.stop="rename('segment', item)"> <div class="SegmentGroupBtn" @click.stop="rename('segment', item)">
{{ $t('trials:reading:Segmentations:button:renameSegmentGroup') }} {{ $t('trials:reading:Segmentations:button:renameSegmentGroup') }}
@ -245,7 +242,7 @@
</template> </template>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
<div class="saveBtnBox"> <div class="saveBtnBox" v-if="readingTaskState < 2">
<el-button type="success" size="small" :disabled="saveLoading" @click="saveSegmentGroup()"> <el-button type="success" size="small" :disabled="saveLoading" @click="saveSegmentGroup()">
{{ $t("trials:reading:Segmentations:button:saveAll") }} {{ $t("trials:reading:Segmentations:button:saveAll") }}
</el-button> </el-button>
@ -261,6 +258,8 @@ import * as cornerstoneAdapters from "@cornerstonejs/adapters";
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader' import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent' import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
import { getCustomizeStandardsSegmentDicomTools } from './toolConfig' import { getCustomizeStandardsSegmentDicomTools } from './toolConfig'
import * as polySeg from '@cornerstonejs/polymorphic-segmentation'
cornerstoneTools.init({ addons: { polySeg } })
const { const {
ToolGroupManager, ToolGroupManager,
Enums: csToolsEnums, Enums: csToolsEnums,
@ -271,6 +270,7 @@ const {
CrosshairsTool, CrosshairsTool,
utilities: CStUtils, utilities: CStUtils,
} = cornerstoneTools; } = cornerstoneTools;
const { MouseBindings, Events: toolsEvents } = csToolsEnums const { MouseBindings, Events: toolsEvents } = csToolsEnums
const { segmentation: segmentationUtils } = CStUtils; const { segmentation: segmentationUtils } = CStUtils;
const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone; const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone;
@ -305,12 +305,32 @@ export default {
return {} return {}
} }
}, },
SegmentConfig: {
type: Object,
default: () => {
return {}
}
},
actionConfiguration: { actionConfiguration: {
type: Object, type: Object,
default: () => { default: () => {
return {} return {}
} }
}, },
curSegSeries: {
type: Object,
default: () => {
return {}
}
},
segId: {
type: String,
default: ''
},
segIndex: {
type: Number,
default: 0
},
renderingEngineId: { renderingEngineId: {
type: String, type: String,
required: true required: true
@ -343,16 +363,6 @@ export default {
ThresholdTools: ['ThresholdCircle', 'ThresholdSphere'], ThresholdTools: ['ThresholdCircle', 'ThresholdSphere'],
thresholdType: null, thresholdType: null,
showSegmentConfig: false, showSegmentConfig: false,
SegmentConfig: {
renderOutline: true,
renderFill: true,
fillAlpha: 0.5,
outlineWidth: 1,
InactiveSegmentations: {
show: true,
fillAlpha: 0.3,
}
},
segmentList: [], segmentList: [],
segmentationId: "", segmentationId: "",
segmentIndex: null, segmentIndex: null,
@ -368,7 +378,7 @@ export default {
'#ff994d', '#ff994d',
'#fb628b', '#fb628b',
], ],
viewprotIds: ['viewport-0', 'viewport-1', 'viewport-2', 'viewport-3', 'viewport-MPR-0', 'viewport-MPR-1', 'viewport-MPR-2'], // viewportIds: [], //
statsKey: [], statsKey: [],
drawing: false, // drawing: false, //
// isDel: false, // isDel: false,
@ -388,14 +398,24 @@ export default {
this.segmentationModifiedCallback this.segmentationModifiedCallback
); );
DicomEvent.$on('activeSeries', (series) => { 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.series = series
this.$emit("update:curSegSeries", Object.assign(series, {}))
this.getSegmentationList()
}) })
DicomEvent.$on('isloaded', (data) => { DicomEvent.$on('isloaded', (data) => {
if (this.isloaded) return false let { segment, isChange = true, viewportId, series } = data
this.isloaded = true DicomEvent.$emit('renderSegmentation', viewportId)
let { segment, isChange = true } = data // if (!series.TaskInfo || series.TaskInfo.VisitTaskId !== this.visitInfo.VisitTaskId) return false
this.delAllSegment(isChange) // if (this.isloaded) return false
this.getSegmentationList(segment) // this.isloaded = true
// this.series = series
// this.viewportIds = []
// this.viewportIds.push(viewportId)
// // this.delAllSegment(isChange)
// this.readingSegmentToViewport(segment)
}) })
const digitPlaces = Number(localStorage.getItem('digitPlaces')) const digitPlaces = Number(localStorage.getItem('digitPlaces'))
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
@ -414,12 +434,15 @@ export default {
s = this.curSegmentGroup.segments.find(item => item.segmentIndex === this.segmentIndex) s = this.curSegmentGroup.segments.find(item => item.segmentIndex === this.segmentIndex)
} }
return s return s
},
readingTaskState() {
return this.series.TaskInfo ? this.series.TaskInfo.ReadingTaskState : 0
} }
}, },
watch: { watch: {
SegmentConfig: { SegmentConfig: {
handler() { handler() {
this.readingSegmentByConfig() // this.readingSegmentByConfig()
}, },
deep: true deep: true
}, },
@ -434,9 +457,23 @@ export default {
this.setBrushThreshold() this.setBrushThreshold()
}, },
deep: true deep: true
},
segmentIndex() {
this.$emit('update:segIndex', this.segmentIndex)
},
segmentationId() {
this.$emit('update:segId', this.segmentationId)
} }
}, },
methods: { methods: {
showSurface(item) {
this.$emit("showSurface", {
segmentationId: item.segmentationId,
segmentIndex: item.segmentIndex,
volumeId: this.series.SeriesInstanceUid,
segmentations: this.curSegmentGroup
})
},
handleClickPopover(item) { handleClickPopover(item) {
this.popoverId = `popover-${item.segmentationId}_${item.segmentIndex}` this.popoverId = `popover-${item.segmentationId}_${item.segmentIndex}`
}, },
@ -504,7 +541,6 @@ export default {
segmentationId: list[0].segmentationId, segmentationId: list[0].segmentationId,
segmentIndices: list.map(item => item.segmentIndex), segmentIndices: list.map(item => item.segmentIndex),
}); });
console.log(bidirectionalData, list[0].segmentationId, 'bidirectionalData')
if (bidirectionalData.length <= 0) { if (bidirectionalData.length <= 0) {
list.forEach(item => { list.forEach(item => {
let annotations = annotation.state.getAllAnnotations().filter(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex); 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) { setToolActive(toolName) {
// if (!this.series.TaskInfo || this.series.TaskInfo.VisitTaskId !== this.visitInfo.VisitTaskId) return false
if (this.segmentList.length <= 0) return false if (this.segmentList.length <= 0) return false
if (this.curSegment.lock) return false if (this.curSegment.lock) return false
if (this.histogramVisible && !this.ThresholdTools.includes(toolName)) return false if (this.histogramVisible && !this.ThresholdTools.includes(toolName)) return false
@ -602,71 +639,33 @@ export default {
viewBidirectional(arr, view) { viewBidirectional(arr, view) {
for (let j = 0; j < arr.length; j++) { for (let j = 0; j < arr.length; j++) {
let item = arr[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 item.bidirectionalView = view
if (!bidirectional) continue // let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view) // item.bidirectionalView = view
// if (!bidirectional) continue
// annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view)
} }
this.resetViewport() DicomEvent.$emit('viewBidirectional', arr)
// this.resetViewport()
}, },
async jumpBidirectional(item) { async jumpBidirectional(item) {
if (item.bidirectional) { DicomEvent.$emit('jumpBidirectional', item)
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 });
}
}
}, },
viewSegmentGroup(item) { viewSegmentGroup(item) {
let view = !item.view item.view = !item.view
this.viewprotIds.forEach(id => {
segmentation.config.visibility.setSegmentationRepresentationVisibility(
id,
{
segmentationId: item.segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
},
view
);
})
item.view = view
item.segments.forEach(i => { item.segments.forEach(i => {
i.view = view i.view = item.view
// this.viewBidirectional(i, view)
}) })
this.viewBidirectional(item.segments, view) DicomEvent.$emit('viewSegmentation', item)
// this.viewBidirectional(item.segments, view)
}, },
viewSegment(item, 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 item.view = view
this.viewBidirectional([item], view)
this.$emit('setToolsPassive') this.$emit('setToolsPassive')
DicomEvent.$emit('viewSegment', item)
}, },
lockSegment(item, lock) { lockSegment(item, lock) {
if (this.readingTaskState >= 2) return false
segmentation.segmentLocking.setSegmentIndexLocked(item.segmentationId, item.segmentIndex, lock) segmentation.segmentLocking.setSegmentIndexLocked(item.segmentationId, item.segmentIndex, lock)
item.lock = lock item.lock = lock
if (!lock) this.changeSegmentationSavedStatus(item.segmentationId, lock) if (!lock) this.changeSegmentationSavedStatus(item.segmentationId, lock)
@ -676,7 +675,7 @@ export default {
this.segmentationId = item.segmentationId; this.segmentationId = item.segmentationId;
this.segmentIndex = item.segmentIndex; this.segmentIndex = item.segmentIndex;
} }
segmentation.segmentIndex.setActiveSegmentIndex(item.segmentationId, item.segmentIndex); // segmentation.segmentIndex.setActiveSegmentIndex(item.segmentationId, item.segmentIndex);
if (isChange) { this.jumpBidirectional(item) } if (isChange) { this.jumpBidirectional(item) }
if (item.lock) { if (item.lock) {
@ -685,15 +684,14 @@ export default {
// this.resetViewport() // this.resetViewport()
}, },
selectSegmentGroup(s) { selectSegmentGroup(s) {
this.viewprotIds.forEach(id => { // segmentation.activeSegmentation.setActiveSegmentation(`${this.viewportKey}-${this.activeViewportIndex}`, this.segmentationId)
segmentation.activeSegmentation.setActiveSegmentation(id, this.segmentationId)
})
let segment = s ? s : this.segmentList.find(item => item.segmentationId === this.segmentationId).segments[0] let segment = s ? s : this.segmentList.find(item => item.segmentationId === this.segmentationId).segments[0]
this.selectSegment(segment, s ? false : true) this.segmentIndex = segment.segmentIndex
this.readingSegmentByConfig() // this.selectSegment(segment, s ? false : true)
// this.readingSegmentByConfig()
}, },
async addSegmentGroup() { async addSegmentGroup() {
let viewprotIds = this.viewprotIds let viewportIds = this.viewportIds
// let segmentationId = this.$guid(); // let segmentationId = this.$guid();
let obj = { let obj = {
name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + (this.segmentList.length + 1), name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + (this.segmentList.length + 1),
@ -723,13 +721,14 @@ export default {
await this.createSegmentation(obj.segmentationId) await this.createSegmentation(obj.segmentationId)
this.createSegmentationRepresentation(obj.segmentationId) this.createSegmentationRepresentation(obj.segmentationId)
this.segmentIndex = 1 this.segmentIndex = 1
viewprotIds.forEach(id => { this.changeColor(this.colors[0], { segmentationId: obj.segmentationId, segmentIndex: 1, color: this.colors[0] })
segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, 1, this.hex2Rgb(this.colors[0])) // viewportIds.forEach(id => {
}) // segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, 1, this.hex2Rgb(this.colors[0]))
// })
this.selectSegmentGroup() this.selectSegmentGroup()
}, },
async addSegment() { async addSegment() {
let viewprotIds = this.viewprotIds; let viewportIds = this.viewportIds;
if (this.segmentList.length <= 0) { if (this.segmentList.length <= 0) {
let obj = { let obj = {
name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + 1, name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + 1,
@ -759,10 +758,11 @@ export default {
this.createSegmentationRepresentation(this.segmentationId) this.createSegmentationRepresentation(this.segmentationId)
this.segmentIndex = 1 this.segmentIndex = 1
segmentation.segmentIndex.setActiveSegmentIndex(this.segmentList[0].segmentationId, 1); segmentation.segmentIndex.setActiveSegmentIndex(this.segmentList[0].segmentationId, 1);
viewprotIds.forEach(id => { this.changeColor(this.colors[0], { segmentationId: this.segmentList[0].segmentationId, segmentIndex: 1, color: this.colors[0] })
segmentation.config.color.setSegmentIndexColor(id, this.segmentList[0].segmentationId, 1, this.hex2Rgb(this.colors[0])) // viewportIds.forEach(id => {
}) // segmentation.config.color.setSegmentIndexColor(id, this.segmentList[0].segmentationId, 1, this.hex2Rgb(this.colors[0]))
this.readingSegmentByConfig() // })
// this.readingSegmentByConfig()
} else { } else {
let item = this.segmentList.find(i => i.segmentationId === this.segmentationId) 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 }) let id = await this.addOrUpdateSegment({ name: obj.SegmentLabel, color: obj.color, segmentIndex: obj.segmentIndex, segmentationId: obj.segmentationId })
obj.id = id obj.id = id
item.segments.push(obj) 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 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) { changeColor(e, item) {
this.viewprotIds.forEach(id => { DicomEvent.$emit('changeColor', item)
segmentation.config.color.setSegmentIndexColor(id, item.segmentationId, item.segmentIndex, this.hex2Rgb(e)) // this.viewportIds.forEach(id => {
}) // segmentation.config.color.setSegmentIndexColor(id, item.segmentationId, item.segmentIndex, this.hex2Rgb(e))
// })
}, },
// //
delAllSegment(isChange) { delAllSegment(isChange) {
@ -836,7 +839,7 @@ export default {
} else { } else {
this.segmentationId = '' this.segmentationId = ''
} }
this.readingSegmentByConfig() // this.readingSegmentByConfig()
this.resetViewport() this.resetViewport()
this.$emit('resetQuestion') this.$emit('resetQuestion')
}, },
@ -868,11 +871,7 @@ export default {
}, },
resetViewport(passive = true) { resetViewport(passive = true) {
let renderingEngine = getRenderingEngine(this.renderingEngineId) DicomEvent.$emit('resetViewport')
this.viewprotIds.forEach(id => {
const viewport = renderingEngine.getViewport(id)
viewport.render()
})
if (passive) this.$emit('setToolsPassive') if (passive) this.$emit('setToolsPassive')
}, },
async rename(key, item) { async rename(key, item) {
@ -925,7 +924,7 @@ export default {
// //
changeInactiveSegmentShow() { changeInactiveSegmentShow() {
let segmentList = this.segmentList.filter(item => item.segmentationId !== this.segmentationId) let segmentList = this.segmentList.filter(item => item.segmentationId !== this.segmentationId)
this.viewprotIds.forEach(id => { this.viewportIds.forEach(id => {
segmentation.config.visibility.setSegmentationRepresentationVisibility( segmentation.config.visibility.setSegmentationRepresentationVisibility(
id, id,
{ {
@ -967,6 +966,7 @@ export default {
this.exportSegmentation(this.segmentationId, group, true) this.exportSegmentation(this.segmentationId, group, true)
}, },
exportSegmentation(segmentationId, group, isFile = false) { exportSegmentation(segmentationId, group, isFile = false) {
try {
const segmentationIds = segmentation.state const segmentationIds = segmentation.state
.getSegmentations() .getSegmentations()
.map(x => x.segmentationId); .map(x => x.segmentationId);
@ -1074,6 +1074,10 @@ export default {
} else { } else {
this.downloadDICOMData(generatedSegmentation.dataset, `${group.name}.dcm`); this.downloadDICOMData(generatedSegmentation.dataset, `${group.name}.dcm`);
} }
} catch (err) {
console.log(err)
}
}, },
downloadDICOMData(bufferOrDataset, filename) { downloadDICOMData(bufferOrDataset, filename) {
let blob; let blob;
@ -1123,7 +1127,7 @@ export default {
const arrayBuffer = image.data.byteArray.buffer; const arrayBuffer = image.data.byteArray.buffer;
await this.loadSegmentation(arrayBuffer, obj.segmentationId); await this.loadSegmentation(arrayBuffer, obj.segmentationId);
this.createSegmentationRepresentation(obj.segmentationId); // this.createSegmentationRepresentation(obj.segmentationId);
}, },
async loadSegmentation(arrayBuffer, segmentationId) { async loadSegmentation(arrayBuffer, segmentationId) {
const generateToolState = const generateToolState =
@ -1306,17 +1310,11 @@ export default {
} }
}, },
createSegmentationRepresentation(segmentationId) { createSegmentationRepresentation(segmentationId) {
this.viewprotIds.forEach(id => { DicomEvent.$emit('createSegmentationRepresentation', segmentationId)
segmentation.addSegmentationRepresentations(id, [
{
segmentationId,
type: csToolsEnums.SegmentationRepresentations.Labelmap,
},
])
})
this.$emit('setToolsPassive') this.$emit('setToolsPassive')
}, },
contentMouseup() { contentMouseup() {
try {
// console.log("segment contentMouseup") // console.log("segment contentMouseup")
if (!this.drawing) return false if (!this.drawing) return false
if (this.timeoutId) { if (this.timeoutId) {
@ -1345,12 +1343,16 @@ export default {
} }
}, 500); }, 500);
} catch (err) {
console.log(err)
}
}, },
// //
async getSegmentBindingList(param = {}) { async getSegmentBindingList(param = {}) {
try { try {
let data = { let data = {
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
PageSize: 9999, PageSize: 9999,
PageIndex: 1, PageIndex: 1,
} }
@ -1367,7 +1369,7 @@ export default {
async saveSegmentBindingAndAnswer(list) { async saveSegmentBindingAndAnswer(list) {
try { try {
let data = { let data = {
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
BindingList: list BindingList: list
} }
let res = await saveSegmentBindingAndAnswer(data) let res = await saveSegmentBindingAndAnswer(data)
@ -1482,7 +1484,7 @@ export default {
let bidirectional = bidirectionalData[0] let bidirectional = bidirectionalData[0]
const { segmentIndex } = bidirectional; const { segmentIndex } = bidirectional;
const { majorAxis, minorAxis, maxMajor, maxMinor } = bidirectional; const { majorAxis, minorAxis } = bidirectional;
let item = list.find(i => i.segmentIndex === segmentIndex) let item = list.find(i => i.segmentIndex === segmentIndex)
SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], { SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], {
segmentIndex, 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"); let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
if (an) { if (an) {
annotation.locking.setAnnotationLocked(an.annotationUID, true) annotation.locking.setAnnotationLocked(an.annotationUID, true)
annotation.visibility.setAnnotationVisibility(an.annotationUID, item.bidirectionalView) annotation.visibility.setAnnotationVisibility(an.annotationUID, true)
} }
item.bidirectional = bidirectional item.bidirectional = bidirectional
reslove(true) reslove(true)
@ -1536,7 +1538,7 @@ export default {
SegmentId: item.SegmentId, SegmentId: item.SegmentId,
SegmentationId: item.SegmentationId, SegmentationId: item.SegmentationId,
TableQuestionId: item.TableQuestionId, TableQuestionId: item.TableQuestionId,
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
} }
bindingList.push(o) bindingList.push(o)
} }
@ -1554,7 +1556,7 @@ export default {
SubjectId: this.visitInfo.SubjectId, SubjectId: this.visitInfo.SubjectId,
SubjectVisitId: this.visitInfo.VisistId, SubjectVisitId: this.visitInfo.VisistId,
TrialId: this.$route.query.trialId, TrialId: this.$route.query.trialId,
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
} }
if (url) data.SegUrl = url; if (url) data.SegUrl = url;
if (id) data.Id = id; if (id) data.Id = id;
@ -1574,7 +1576,7 @@ export default {
try { try {
let data = { let data = {
SeriesId: this.series.Id, SeriesId: this.series.Id,
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
PageSize: 9999, PageSize: 9999,
PageIndex: 1, PageIndex: 1,
} }
@ -1583,6 +1585,8 @@ export default {
this.loading = false; this.loading = false;
if (res.IsSuccess) { if (res.IsSuccess) {
this.segmentList = [] this.segmentList = []
this.segmentationId = null;
this.segmentIndex = null;
let list = res.Result.CurrentPageData; let list = res.Result.CurrentPageData;
for (let i = 0; i < list.length; i++) { for (let i = 0; i < list.length; i++) {
let item = list[i] let item = list[i]
@ -1597,12 +1601,12 @@ export default {
segments: [] segments: []
} }
this.segmentList.push(obj) this.segmentList.push(obj)
if (item.SEGUrl) { // if (item.SEGUrl) {
await this.readSegmentation(obj) // await this.readSegmentation(obj)
} else { // } else {
await this.createSegmentation(obj.segmentationId) // await this.createSegmentation(obj.segmentationId)
this.createSegmentationRepresentation(obj.segmentationId) // // this.createSegmentationRepresentation(obj.segmentationId)
} // }
} }
if (!this.segmentationId) { if (!this.segmentationId) {
this.segmentationId = obj.segmentationId this.segmentationId = obj.segmentationId
@ -1621,45 +1625,41 @@ export default {
bidirectional: SegmentJson.bidirectional, bidirectional: SegmentJson.bidirectional,
bidirectionalView: true, bidirectionalView: true,
view: true, view: true,
lock: item.locked, lock: true,
id: s.Id id: s.Id
} }
obj.segments.push(o) obj.segments.push(o)
this.selectSegment(o, false) // this.selectSegment(o, false)
this.changeColor(s.ColorRgb, o) // this.changeColor(s.ColorRgb, o)
this.lockSegment(o, true) // this.lockSegment(o, true)
} }
if (!this.segmentIndex) { if (!this.segmentIndex) {
this.segmentIndex = s.SegmentNumber this.segmentIndex = s.SegmentNumber
} }
}) })
this.$nextTick(() => { // this.$nextTick(() => {
if (SEGMENT) { // if (SEGMENT) {
// console.log(SEGMENT, 'SEGMENT') // // console.log(SEGMENT, 'SEGMENT')
return this.getBidirectional(obj.segments, SEGMENT) // return this.getBidirectional(obj.segments, SEGMENT)
} // }
this.getBidirectional(obj.segments, null, false) // 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)
} }
// 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.isloaded = false
this.readingSegmentByConfig() // this.readingSegmentByConfig()
} }
} catch (err) { } catch (err) {
this.loading = false this.loading = false
@ -1688,7 +1688,7 @@ export default {
SegmentName: name, SegmentName: name,
SegmentNumber: segmentIndex, SegmentNumber: segmentIndex,
SegmentationId: segmentationId, SegmentationId: segmentationId,
VisitTaskId: this.visitInfo.VisitTaskId, VisitTaskId: this.series.TaskInfo.VisitTaskId,
SegmentJson: segmentJson SegmentJson: segmentJson
} }
if (id) data.Id = id if (id) data.Id = id

View File

@ -14,6 +14,25 @@
<div v-if="imageInfo.total">Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}</div> <div v-if="imageInfo.total">Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}</div>
<div>{{ series.Modality }}</div> <div>{{ series.Modality }}</div>
</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 v-if="series" class="right-top-text">
<div>{{ series.Description }}</div> <div>{{ series.Description }}</div>
</div> </div>
@ -83,6 +102,19 @@ import {
setPetTransferFunctionForVolumeActor setPetTransferFunctionForVolumeActor
} from './helpers/index.js' } from './helpers/index.js'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent' 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 { export default {
name: 'MPRViewport', name: 'MPRViewport',
props: { props: {
@ -101,6 +133,32 @@ export default {
histogramVisible: { histogramVisible: {
type: Boolean, type: Boolean,
default: false 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() { data() {
@ -154,6 +212,39 @@ export default {
this.$nextTick(() => { this.$nextTick(() => {
this.initViewport() 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: { watch: {
MPRInfo: { MPRInfo: {
@ -172,6 +263,25 @@ export default {
} }
}, },
deep: true 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: { methods: {
@ -549,13 +659,9 @@ export default {
console.log("渲染成功") console.log("渲染成功")
} }
}]).then(r => { }]).then(r => {
if (data.segment) {
return DicomEvent.$emit("isloaded", { segment: data.segment, isChange: data.isChange })
}
if (data.isLocation) { if (data.isLocation) {
setTimeout(() => { csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); }) setTimeout(() => { csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); })
} }
DicomEvent.$emit("isloaded", { isChange: data.isChange })
}) })
viewport.render() viewport.render()
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') { if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
@ -567,11 +673,10 @@ export default {
renderingEngine.render() renderingEngine.render()
}, 100) }, 100)
} }
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.segmentationId, this.segmentIndex, this.renderingEngineId, data.segment, this.actionConfiguration)
} catch (e) { } catch (e) {
console.log(e) console.log(e)
} }
}, },
cornerstoneToolsMouseMove(e) { cornerstoneToolsMouseMove(e) {
const { currentPoints } = e.detail const { currentPoints } = e.detail

View File

@ -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
}