SPECT融合更改
parent
9a3e972723
commit
77a633d699
|
|
@ -2,9 +2,9 @@
|
|||
<div ref="viewport-fusion" class="viewport-wrapper" v-loading="loading" :element-loading-text="NSTip"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)" @mouseup="sliderMouseup" @mousemove="sliderMousemove"
|
||||
@mouseleave="sliderMouseleave" :style="{ color: series.Modality === 'PT' || series.Modality === 'NM' || isMip ? '#666' : '#ddd' }">
|
||||
<div v-if="isFusion && series.Modality === 'NM'" class="opacity-slider-wrapper" @mousedown.stop @mousemove.stop @mouseup.stop @wheel.stop>
|
||||
<div class="slider-title">{{ Math.round(nmOpacity * 100) }}%</div>
|
||||
<input type="range" min="0" max="1" step="0.05" v-model.number="nmOpacity" @input="applyNmOpacity"
|
||||
<div v-if="isFusion" class="opacity-slider-wrapper" @mousedown.stop @mousemove.stop @mouseup.stop @wheel.stop>
|
||||
<div class="slider-title">{{ Math.round(fusionOpacity * 100) }}%</div>
|
||||
<input type="range" min="0" max="1" step="0.05" v-model.number="fusionOpacity" @input="applyFusionOpacity"
|
||||
class="opacity-slider" />
|
||||
</div>
|
||||
<div v-if="series && taskInfo" class="left-top-text">
|
||||
|
|
@ -22,29 +22,13 @@
|
|||
<div v-if="isFusion">{{ ctSeries.Modality }} / {{ series.Modality }}</div>
|
||||
<div v-if="isMip">MIP</div>
|
||||
</div>
|
||||
<!-- <div v-if="series && taskInfo && taskInfo.IsReadingTaskViewInOrder === 1 && series.TaskInfo && !isMip && !isFusion"
|
||||
class="top-center-tool">
|
||||
<div class="toggle-visit-container">
|
||||
<div class="arrw_icon"
|
||||
:style="{ cursor: series.TaskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: 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.TaskBlindName }}
|
||||
</div>
|
||||
<div class="arrw_icon"
|
||||
:style="{ cursor: series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: 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 && !isMip && !isFusion" class="right-top-text">
|
||||
<div>{{ series.Description }}</div>
|
||||
</div>
|
||||
<div v-if="isFusion && !isMip" class="fusion-order-toggle" @mousedown.stop @mouseup.stop
|
||||
@click.stop="toggleFusionRenderOrder">
|
||||
{{ fusionCtOnTop ? `${ctSeries.Modality}/${series.Modality}` : `${series.Modality}/${ctSeries.Modality}` }}
|
||||
</div>
|
||||
<div v-if="series" class="left-bottom-text">
|
||||
<div v-show="mousePosition.index.length > 0 && !isMip">
|
||||
Pos: {{ mousePosition.index[0] }}, {{ mousePosition.index[1] }}, {{ mousePosition.index[2] }}
|
||||
|
|
@ -111,7 +95,7 @@ import {
|
|||
import * as cornerstoneTools from '@cornerstonejs/tools'
|
||||
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader';
|
||||
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps'
|
||||
import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction'
|
||||
|
||||
import { createImageIdsAndCacheMetaData } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/createImageIdsAndCacheMetaData'
|
||||
import setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
|
||||
import { setPetColorMapTransferFunctionForVolumeActor } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setPetColorMapTransferFunctionForVolumeActor'
|
||||
|
|
@ -146,6 +130,7 @@ export default {
|
|||
petSeries: {},
|
||||
isFusion: false,
|
||||
isMip: false,
|
||||
fusionCtOnTop: false,
|
||||
taskInfo: null,
|
||||
sliderInfo: {
|
||||
oldB: null,
|
||||
|
|
@ -185,9 +170,10 @@ export default {
|
|||
},
|
||||
ptVolumeId: null,
|
||||
loading: false,
|
||||
Colorbar: null,
|
||||
nmOpacity: 0.6,
|
||||
nmFusionVolumeActor: null
|
||||
Colorbar: null,
|
||||
fusionOpacity: 0.5,
|
||||
topFusionVolumeActor: null,
|
||||
currentVoiUpper: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -288,6 +274,14 @@ Colorbar: null,
|
|||
}
|
||||
if (properties && properties.voiRange) {
|
||||
var { lower, upper } = properties.voiRange
|
||||
if ((!upper || upper === 0) && this.currentVoiUpper > 0) {
|
||||
upper = this.currentVoiUpper
|
||||
} else if (upper) {
|
||||
this.currentVoiUpper = upper
|
||||
}
|
||||
|
||||
if (!upper) return
|
||||
|
||||
const { windowWidth, windowCenter } = csUtils.windowLevel.toWindowLevel(
|
||||
lower,
|
||||
upper
|
||||
|
|
@ -296,6 +290,9 @@ Colorbar: null,
|
|||
if (this.series.Modality === 'PT' || this.series.Modality === 'NM' || this.isFusion) {
|
||||
this.$emit('upperRangeChange', Math.round(upper))
|
||||
}
|
||||
if (this.isFusion && !this.fusionCtOnTop && this.topFusionVolumeActor) {
|
||||
this.applyFusionOpacity()
|
||||
}
|
||||
}
|
||||
},
|
||||
getOrientationMarker() {
|
||||
|
|
@ -416,6 +413,11 @@ Colorbar: null,
|
|||
voiChange(v) {
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
const voiRange = { lower: 0, upper: v }
|
||||
this.currentVoiUpper = v
|
||||
if (this.isFusion) {
|
||||
console.log('voiChange', v)
|
||||
}
|
||||
|
||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||
if (!viewport) return
|
||||
let volumeId = this.isFusion ? this.ptVolumeId : this.volumeId
|
||||
|
|
@ -425,6 +427,11 @@ Colorbar: null,
|
|||
)
|
||||
|
||||
viewport.setProperties({ voiRange }, volumeId)
|
||||
|
||||
// if (this.isFusion && !this.fusionCtOnTop && this.topFusionVolumeActor) {
|
||||
// this.applyFusionOpacity()
|
||||
// }
|
||||
|
||||
viewportsContainingVolumeUID.forEach((vp) => {
|
||||
vp.render()
|
||||
// this.$refs[vp.id].voiModified()
|
||||
|
|
@ -464,17 +471,21 @@ Colorbar: null,
|
|||
ctx.fillStyle = gradient
|
||||
ctx.fillRect(0, 0, rectWidth, rectHeight)
|
||||
},
|
||||
applyNmOpacity() {
|
||||
if (!this.nmFusionVolumeActor?.getProperty) {
|
||||
return;
|
||||
}
|
||||
const ofun = vtkPiecewiseFunction.newInstance();
|
||||
ofun.addPoint(0, 0.0);
|
||||
ofun.addPoint(0.1, 0.9 * this.nmOpacity);
|
||||
ofun.addPoint(5, 1.0 * this.nmOpacity);
|
||||
this.nmFusionVolumeActor.getProperty().setScalarOpacity(0, ofun);
|
||||
opacityChange(opacity) {
|
||||
this.fusionOpacity = opacity
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
renderingEngine?.render?.();
|
||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||
if (!viewport) return
|
||||
let volumeId = this.isFusion ? this.ptVolumeId : this.volumeId
|
||||
|
||||
viewport.setProperties(
|
||||
{ colormap: { opacity: Number(opacity) } },
|
||||
volumeId
|
||||
)
|
||||
viewport.render()
|
||||
},
|
||||
applyFusionOpacity() {
|
||||
this.opacityChange(this.fusionOpacity)
|
||||
},
|
||||
setPreset(presetName) {
|
||||
this.presetName = presetName
|
||||
|
|
@ -507,6 +518,85 @@ Colorbar: null,
|
|||
})
|
||||
this.loading = false
|
||||
},
|
||||
getFusionVolumes() {
|
||||
const ctVolumeId = this.ctSeries?.SeriesInstanceUid
|
||||
const ptFusionVolumeId = this.ptVolumeId
|
||||
if (!ctVolumeId || !ptFusionVolumeId) {
|
||||
return []
|
||||
}
|
||||
|
||||
const ctEntry = {
|
||||
volumeId: ctVolumeId,
|
||||
callback: (r) => {
|
||||
setCtTransferFunctionForVolumeActor({ ...r, volumeId: ctVolumeId })
|
||||
if (this.fusionCtOnTop) {
|
||||
this.topFusionVolumeActor = r.volumeActor
|
||||
this.applyFusionOpacity()
|
||||
}
|
||||
console.log("融合ct渲染成功")
|
||||
}
|
||||
}
|
||||
|
||||
const ptFusionEntry = {
|
||||
volumeId: ptFusionVolumeId,
|
||||
callback: (r) => {
|
||||
setPetColorMapTransferFunctionForVolumeActor({ ...r, volumeId: ptFusionVolumeId })
|
||||
if (!this.fusionCtOnTop) {
|
||||
this.topFusionVolumeActor = r.volumeActor
|
||||
this.applyFusionOpacity()
|
||||
}
|
||||
console.log("融合pet渲染成功")
|
||||
}
|
||||
}
|
||||
|
||||
const volumes = []
|
||||
if (this.series.Modality !== 'NM') {
|
||||
volumes.push({
|
||||
volumeId: this.volumeId,
|
||||
callback: (r) => {
|
||||
console.log("融合pet渲染成功");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (this.fusionCtOnTop) {
|
||||
volumes.push(ptFusionEntry, ctEntry)
|
||||
} else {
|
||||
volumes.push(ctEntry, ptFusionEntry)
|
||||
}
|
||||
|
||||
return volumes
|
||||
},
|
||||
async applyFusionRenderOrder() {
|
||||
if (!this.isFusion) return
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
const viewport = renderingEngine?.getViewport?.(this.viewportId)
|
||||
if (!viewport) return
|
||||
|
||||
const volumes = this.getFusionVolumes()
|
||||
if (!volumes.length) return
|
||||
|
||||
const camera = viewport.getCamera?.()
|
||||
|
||||
const savedVoiUpper = this.currentVoiUpper
|
||||
|
||||
await viewport.setVolumes(volumes)
|
||||
if (camera) {
|
||||
viewport.setCamera(camera)
|
||||
}
|
||||
|
||||
if (savedVoiUpper) {
|
||||
viewport.setProperties({ voiRange: { lower: 0, upper: savedVoiUpper } }, this.ptVolumeId)
|
||||
}
|
||||
|
||||
viewport.render()
|
||||
},
|
||||
toggleFusionRenderOrder() {
|
||||
if (!this.isFusion) return
|
||||
this.fusionCtOnTop = !this.fusionCtOnTop
|
||||
this.applyFusionRenderOrder()
|
||||
this.$emit('upperRangeChange', Math.round(this.currentVoiUpper))
|
||||
},
|
||||
async setSeriesInfo(obj, isLocate = false, option = {}) {
|
||||
try {
|
||||
let { data } = obj
|
||||
|
|
@ -519,11 +609,12 @@ Colorbar: null,
|
|||
this.volumeId = data.SeriesInstanceUid
|
||||
this.ptVolumeId = null
|
||||
this.series = {}
|
||||
this.nmFusionVolumeActor = null
|
||||
this.topFusionVolumeActor = null
|
||||
let { isFusion, isMip, colorMap } = option
|
||||
this.isFusion = isFusion;
|
||||
this.isMip = isMip;
|
||||
if (this.isFusion) {
|
||||
this.fusionCtOnTop = false
|
||||
this.$nextTick(() => {
|
||||
this.renderColorBar(this.presetName)
|
||||
})
|
||||
|
|
@ -531,34 +622,10 @@ Colorbar: null,
|
|||
let { ct, data } = obj
|
||||
this.series = { ...data }
|
||||
this.ctSeries = { ...ct }
|
||||
let volumes = [
|
||||
{
|
||||
volumeId: ct.SeriesInstanceUid, callback: (r) => {
|
||||
setCtTransferFunctionForVolumeActor(r)
|
||||
console.log("融合ct渲染成功")
|
||||
}
|
||||
},
|
||||
{
|
||||
volumeId: this.ptVolumeId, callback: (r) => {
|
||||
setPetColorMapTransferFunctionForVolumeActor(r)
|
||||
if (this.series.Modality === 'NM') {
|
||||
this.nmFusionVolumeActor = r.volumeActor
|
||||
this.applyNmOpacity()
|
||||
}
|
||||
console.log("融合pet渲染成功")
|
||||
}
|
||||
},
|
||||
]
|
||||
if (this.series.Modality !== 'NM') {
|
||||
volumes.unshift({
|
||||
volumeId: this.volumeId, callback: (r) => {
|
||||
// setPetColorMapTransferFunctionForVolumeActor(r)
|
||||
console.log("融合pet渲染成功");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
await viewport.setVolumes(volumes)
|
||||
|
||||
|
||||
await viewport.setVolumes(this.getFusionVolumes())
|
||||
} else {
|
||||
this.series = { ...data }
|
||||
if (this.isMip) {
|
||||
|
|
@ -593,9 +660,9 @@ Colorbar: null,
|
|||
volumeId: this.volumeId, callback: (r) => {
|
||||
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
|
||||
// setPetColorMapTransferFunctionForVolumeActor(r, true)
|
||||
setPetTransferFunctionForVolumeActor(r)
|
||||
setPetTransferFunctionForVolumeActor({ ...r, volumeId: this.volumeId })
|
||||
} else {
|
||||
setCtTransferFunctionForVolumeActor(r)
|
||||
setCtTransferFunctionForVolumeActor({ ...r, volumeId: this.volumeId })
|
||||
}
|
||||
}
|
||||
}])
|
||||
|
|
@ -603,6 +670,7 @@ Colorbar: null,
|
|||
|
||||
}
|
||||
viewport.render()
|
||||
this.voiChange(this.currentVoiUpper)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
|
@ -782,7 +850,7 @@ Colorbar: null,
|
|||
},
|
||||
beforeDestroy() {
|
||||
this.series = null
|
||||
this.nmFusionVolumeActor = null
|
||||
this.topFusionVolumeActor = null
|
||||
},
|
||||
computed: {
|
||||
NSTip() {
|
||||
|
|
@ -892,6 +960,20 @@ Colorbar: null,
|
|||
font-size: 12px;
|
||||
}
|
||||
|
||||
.fusion-order-toggle {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
z-index: 2;
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.left-bottom-text {
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
|
|
|
|||
|
|
@ -273,8 +273,12 @@
|
|||
</div>
|
||||
<!-- 伪彩 -->
|
||||
<template v-if="readingTool === 2">
|
||||
<colorMap v-show="isFusion" ref="colorMap" :unit="fusionOverlayModality === 'NM' ? 'counts' : 'g/ml'"
|
||||
:modality="fusionOverlayModality" @setColorMap="setColorMap" @voiChange="voiChange" />
|
||||
<colorMap
|
||||
v-show="isFusion"
|
||||
ref="colorMap"
|
||||
:modality="fusionOverlayModality"
|
||||
@setColorMap="setColorMap"
|
||||
@voiChange="voiChange" />
|
||||
</template>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
<el-input v-model="range" size="mini" style="width:120px" :maxlength="maxLength"
|
||||
oninput="if(value){value=value.replace(/[^\d]/g,'')} if(value<=0){value=''}"
|
||||
@change="upperRangeChange">
|
||||
<template slot="append">{{ unit }}</template>
|
||||
<template slot="append">g/ml</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div id="slider" style="position: absolute;left: 6px;top:5px;cursor: pointer;">
|
||||
|
|
@ -55,10 +55,6 @@ const { registerColormap, getColormapNames, getColormap } = csUtils.colormap
|
|||
export default {
|
||||
name: "colorMap",
|
||||
props: {
|
||||
unit: {
|
||||
type: String,
|
||||
default: 'g/ml'
|
||||
},
|
||||
modality: {
|
||||
type: String,
|
||||
default: ''
|
||||
|
|
@ -163,6 +159,7 @@ export default {
|
|||
position = parseInt((position / maxLeft) * upper)
|
||||
if (position > upper) position = upper
|
||||
if (position < 0) position = 0
|
||||
|
||||
if (this.modality === 'NM') {
|
||||
positionValue.textContent = upper > 0 ? Math.round((position / upper) * 100) + '%' : '0%'
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in New Issue