在影像上传预览和质控预览工具中,增加DICOM标签查看工具
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
9e786c53b8
commit
709063a26e
|
@ -81,16 +81,25 @@
|
||||||
<!-- <div v-show="stack.firstImageLoading" class="load-indicator">
|
<!-- <div v-show="stack.firstImageLoading" class="load-indicator">
|
||||||
Loading Series #{{ stack.seriesNumber }}...
|
Loading Series #{{ stack.seriesNumber }}...
|
||||||
</div>-->
|
</div>-->
|
||||||
|
<el-dialog
|
||||||
|
v-if="dcmTag.visible"
|
||||||
|
:visible.sync="dcmTag.visible"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:title="dcmTag.title"
|
||||||
|
width="1000px"
|
||||||
|
custom-class="base-dialog-wrapper"
|
||||||
|
append-to-body
|
||||||
|
>
|
||||||
|
<DicomTags :image-data="imageData" @close="dcmTag.visible = false" />
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Vue from 'vue'
|
|
||||||
import Contextmenu from 'vue-contextmenujs'
|
|
||||||
Vue.use(Contextmenu)
|
|
||||||
import * as cornerstone from 'cornerstone-core'
|
import * as cornerstone from 'cornerstone-core'
|
||||||
import * as cornerstoneMath from 'cornerstone-math'
|
import * as cornerstoneMath from 'cornerstone-math'
|
||||||
import * as cornerstoneTools from 'cornerstone-tools'
|
import * as cornerstoneTools from 'cornerstone-tools'
|
||||||
|
|
||||||
const scroll = cornerstoneTools.import('util/scrollToIndex')
|
const scroll = cornerstoneTools.import('util/scrollToIndex')
|
||||||
import Hammer from 'hammerjs'
|
import Hammer from 'hammerjs'
|
||||||
import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString'
|
import getOrientationString from '@/views/trials/trials-panel/reading/dicoms/tools/OrientationMarkers/getOrientationString'
|
||||||
|
@ -108,8 +117,10 @@ cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)')
|
||||||
// cornerstoneTools.init({ showSVGCursors: true })
|
// cornerstoneTools.init({ showSVGCursors: true })
|
||||||
cornerstoneTools.init()
|
cornerstoneTools.init()
|
||||||
const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager
|
const ToolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager
|
||||||
|
import DicomTags from './DicomTags'
|
||||||
export default {
|
export default {
|
||||||
name: 'DicomCanvas',
|
name: 'DicomCanvas',
|
||||||
|
components: { DicomTags },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
|
@ -164,7 +175,9 @@ export default {
|
||||||
mousePosition: { x: '', y: '', mo: '' },
|
mousePosition: { x: '', y: '', mo: '' },
|
||||||
markers: { top: '', right: '', bottom: '', left: '' },
|
markers: { top: '', right: '', bottom: '', left: '' },
|
||||||
orientationMarkers: [],
|
orientationMarkers: [],
|
||||||
originalMarkers: []
|
originalMarkers: [],
|
||||||
|
dcmTag: { visible: false, title: 'DICOM Tags' },
|
||||||
|
imageData: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -215,7 +228,7 @@ export default {
|
||||||
cornerstoneTools.stopClip(this.canvas)
|
cornerstoneTools.stopClip(this.canvas)
|
||||||
this.toolState.clipPlaying = false
|
this.toolState.clipPlaying = false
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
|
||||||
cornerstone.loadAndCacheImage(this.stack.imageIds[this.stack.currentImageIdIndex])
|
cornerstone.loadAndCacheImage(this.stack.imageIds[this.stack.currentImageIdIndex])
|
||||||
.then(image => {
|
.then(image => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
@ -364,8 +377,8 @@ export default {
|
||||||
if (this.dicomInfo.thick) {
|
if (this.dicomInfo.thick) {
|
||||||
this.dicomInfo.thick = this.dicomInfo.thick.toFixed(2)
|
this.dicomInfo.thick = this.dicomInfo.thick.toFixed(2)
|
||||||
}
|
}
|
||||||
let newImageIdIndex = this.stack.imageIds.findIndex(i=>i===e.detail.image.imageId)
|
const newImageIdIndex = this.stack.imageIds.findIndex(i => i === e.detail.image.imageId)
|
||||||
if(newImageIdIndex === -1) return
|
if (newImageIdIndex === -1) return
|
||||||
this.stack.currentImageIdIndex = newImageIdIndex
|
this.stack.currentImageIdIndex = newImageIdIndex
|
||||||
this.stack.imageIdIndex = newImageIdIndex
|
this.stack.imageIdIndex = newImageIdIndex
|
||||||
this.series.imageIdIndex = newImageIdIndex
|
this.series.imageIdIndex = newImageIdIndex
|
||||||
|
@ -441,7 +454,7 @@ export default {
|
||||||
if (!markers) {
|
if (!markers) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.orientationMarkers = [oppositeColumn, row, column, oppositeRow]
|
this.orientationMarkers = [oppositeColumn, row, column, oppositeRow]
|
||||||
this.originalMarkers = [oppositeColumn, row, column, oppositeRow]
|
this.originalMarkers = [oppositeColumn, row, column, oppositeRow]
|
||||||
this.setMarkers()
|
this.setMarkers()
|
||||||
|
@ -636,7 +649,7 @@ export default {
|
||||||
enabledElement.renderingTools.renderCanvasData = renderCanvasData
|
enabledElement.renderingTools.renderCanvasData = renderCanvasData
|
||||||
},
|
},
|
||||||
scrollPage(offset) {
|
scrollPage(offset) {
|
||||||
if(this.loading) return
|
if (this.loading) return
|
||||||
var index = this.stack.currentImageIdIndex + offset
|
var index = this.stack.currentImageIdIndex + offset
|
||||||
if (index < 0) index = 0
|
if (index < 0) index = 0
|
||||||
else if (index >= this.stack.imageIds.length) {
|
else if (index >= this.stack.imageIds.length) {
|
||||||
|
@ -648,7 +661,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleClipPlay() {
|
toggleClipPlay() {
|
||||||
if(this.loading) return
|
if (this.loading) return
|
||||||
if (this.toolState.clipPlaying) {
|
if (this.toolState.clipPlaying) {
|
||||||
cornerstoneTools.stopClip(this.canvas)
|
cornerstoneTools.stopClip(this.canvas)
|
||||||
this.toolState.clipPlaying = false
|
this.toolState.clipPlaying = false
|
||||||
|
@ -707,7 +720,7 @@ export default {
|
||||||
this.orientationMarkers = [...this.originalMarkers]
|
this.orientationMarkers = [...this.originalMarkers]
|
||||||
this.setMarkers()
|
this.setMarkers()
|
||||||
}
|
}
|
||||||
|
|
||||||
var viewport = cornerstone.getViewport(this.canvas)
|
var viewport = cornerstone.getViewport(this.canvas)
|
||||||
viewport.hflip = false
|
viewport.hflip = false
|
||||||
viewport.vflip = false
|
viewport.vflip = false
|
||||||
|
@ -747,6 +760,13 @@ export default {
|
||||||
var uid = cornerstone.getImage(this.canvas).data.string('x00080018')
|
var uid = cornerstone.getImage(this.canvas).data.string('x00080018')
|
||||||
cornerstoneTools.SaveAs(this.canvas, `${uid}.png`)
|
cornerstoneTools.SaveAs(this.canvas, `${uid}.png`)
|
||||||
},
|
},
|
||||||
|
showTags() {
|
||||||
|
var image = cornerstone.getImage(this.canvas)
|
||||||
|
// var dataSet = dicomParser.parseDicom(image.data.byteArray)
|
||||||
|
// console.log('showTags', dataSet)
|
||||||
|
this.dcmTag.visible = true
|
||||||
|
this.imageData = image.data
|
||||||
|
},
|
||||||
fitToWindow() {
|
fitToWindow() {
|
||||||
if (this.stack.seriesNumber) {
|
if (this.stack.seriesNumber) {
|
||||||
cornerstone.fitToWindow(this.canvas)
|
cornerstone.fitToWindow(this.canvas)
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
<template>
|
||||||
|
<div class="dcm-tag">
|
||||||
|
<el-input
|
||||||
|
v-model="search"
|
||||||
|
size="mini"
|
||||||
|
placeholder="输入关键字搜索"
|
||||||
|
style="width:200px"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
:data="filterList(list)"
|
||||||
|
row-key="id"
|
||||||
|
default-expand-all
|
||||||
|
:tree-props="{children: 'child', hasChildren: 'hasChildren'}"
|
||||||
|
:default-sort="{prop: 'tagCode', order: 'ascending'}"
|
||||||
|
height="500"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
prop="tagCode"
|
||||||
|
label="Tag"
|
||||||
|
min-width="120"
|
||||||
|
sortable
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="tagName"
|
||||||
|
label="Description"
|
||||||
|
min-width="150"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="vr"
|
||||||
|
label="VR"
|
||||||
|
min-width="50"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="length"
|
||||||
|
label="Length"
|
||||||
|
min-width="80"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
prop="value"
|
||||||
|
label="Value"
|
||||||
|
min-width="200"
|
||||||
|
show-overflow-tooltip
|
||||||
|
sortable
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import TAG_DICT from './dataDictionary'
|
||||||
|
import dicomParser from 'dicom-parser'
|
||||||
|
export default {
|
||||||
|
name: 'DicomTags',
|
||||||
|
props: {
|
||||||
|
imageData: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
list: [],
|
||||||
|
idx: 0,
|
||||||
|
search: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
var dataSet = dicomParser.parseDicom(this.imageData.byteArray)
|
||||||
|
var output = []
|
||||||
|
this.dumpDataSet(dataSet, output)
|
||||||
|
this.list = output
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
filterList(list) {
|
||||||
|
if (list.length === 0) return []
|
||||||
|
if (!this.search) {
|
||||||
|
return list
|
||||||
|
} else {
|
||||||
|
return list.filter(data => data.tagCode.toLowerCase().includes(this.search.toLowerCase()) || data.tagName.toLowerCase().includes(this.search.toLowerCase()) || (data.value && data.value.toLowerCase().includes(this.search.toLowerCase())))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dumpDataSet(dataSet, output) {
|
||||||
|
try {
|
||||||
|
for (const propertyName in dataSet.elements) {
|
||||||
|
const elementObject = {}
|
||||||
|
const element = dataSet.elements[propertyName]
|
||||||
|
const tag = this.getTag(element.tag)
|
||||||
|
elementObject.id = `${this.idx++}${new Date().getTime()}`
|
||||||
|
elementObject.tagCode = element.tag
|
||||||
|
elementObject.tagName = tag.name
|
||||||
|
elementObject.length = element.length
|
||||||
|
|
||||||
|
if (element.vr) {
|
||||||
|
elementObject.vr = element.vr
|
||||||
|
}
|
||||||
|
elementObject.child = []
|
||||||
|
|
||||||
|
if (element.items) {
|
||||||
|
element.items.forEach(item => {
|
||||||
|
const childOutput = []
|
||||||
|
this.dumpDataSet(item.dataSet, childOutput)
|
||||||
|
elementObject.child.push(...childOutput)
|
||||||
|
})
|
||||||
|
} else if (!element.fragments) {
|
||||||
|
if (element.length < 128) {
|
||||||
|
const str = dataSet.string(propertyName)
|
||||||
|
if (this.isASCII(str) && str !== undefined) {
|
||||||
|
elementObject.value = str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementObject.child.length === 0) {
|
||||||
|
elementObject.child = null
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push(elementObject)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
const ex = {
|
||||||
|
exception: err,
|
||||||
|
output: output
|
||||||
|
}
|
||||||
|
throw ex
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getTag(tag) {
|
||||||
|
var group = tag.substring(1, 5)
|
||||||
|
var element = tag.substring(5, 9)
|
||||||
|
var tagIndex = ('(' + group + ',' + element + ')').toUpperCase()
|
||||||
|
var attr = TAG_DICT[tagIndex]
|
||||||
|
return attr
|
||||||
|
},
|
||||||
|
imageFrameLink(frameIndex) {
|
||||||
|
var linkText = "<a class='imageFrameDownload' "
|
||||||
|
linkText += "data-frameIndex='" + frameIndex + "'"
|
||||||
|
linkText += " href='#'> Frame #" + frameIndex + '</a>'
|
||||||
|
return linkText
|
||||||
|
},
|
||||||
|
isASCII(str) {
|
||||||
|
return /^[\x00-\x7F]*$/.test(str)
|
||||||
|
},
|
||||||
|
isStringVr(vr) {
|
||||||
|
if (vr === 'AT' || vr === 'FL' || vr === 'FD' || vr === 'OB' || vr === 'OF' || vr === 'OW' || vr === 'SI' || vr === 'SQ' || vr === 'SS' || vr === 'UL' || vr === 'US') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.dcm-tag{
|
||||||
|
// user-select: none;
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 15px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #d0d0d0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -182,7 +182,7 @@
|
||||||
<svg-icon icon-class="fitToImage" style="font-size:20px;" />
|
<svg-icon icon-class="fitToImage" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
<!-- <button title="旋转" class="btn-link dropdown" data-tool="Rotate" @click="setToolActive($event,'Rotate')"> -->
|
<!-- <button title="旋转" class="btn-link dropdown" data-tool="Rotate" @click="setToolActive($event,'Rotate')"> -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 测量标注 -->
|
<!-- 测量标注 -->
|
||||||
|
@ -233,6 +233,10 @@
|
||||||
<button :title="$t('trials:dicom-show:image')" class="btn-link" @click="currentDicomCanvas.saveImage()">
|
<button :title="$t('trials:dicom-show:image')" class="btn-link" @click="currentDicomCanvas.saveImage()">
|
||||||
<svg-icon icon-class="image" style="font-size:20px;" />
|
<svg-icon icon-class="image" style="font-size:20px;" />
|
||||||
</button>
|
</button>
|
||||||
|
<!-- 标签 -->
|
||||||
|
<button :title="$t('trials:dicom-show:tags')" class="btn-link" @click="currentDicomCanvas.showTags()">
|
||||||
|
<svg-icon icon-class="dictionary" style="font-size:20px;" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="measureTool-wrapper">
|
<div class="measureTool-wrapper">
|
||||||
|
@ -405,7 +409,7 @@ export default {
|
||||||
loadImageStack(dicomSeries) {
|
loadImageStack(dicomSeries) {
|
||||||
this.currentDicomCanvas.toolState.clipPlaying = false
|
this.currentDicomCanvas.toolState.clipPlaying = false
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
let series = Object.assign({}, dicomSeries)
|
const series = Object.assign({}, dicomSeries)
|
||||||
this.currentDicomCanvas.loadImageStack(series)
|
this.currentDicomCanvas.loadImageStack(series)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -416,7 +420,7 @@ export default {
|
||||||
Array.from(elements).forEach((element, index) => {
|
Array.from(elements).forEach((element, index) => {
|
||||||
const canvasIndex = element.getAttribute('data-index')
|
const canvasIndex = element.getAttribute('data-index')
|
||||||
if (index < seriesList.length && element.style.display !== 'none') {
|
if (index < seriesList.length && element.style.display !== 'none') {
|
||||||
let series = Object.assign({}, seriesList[index])
|
const series = Object.assign({}, seriesList[index])
|
||||||
this.$refs[`dicomCanvas${canvasIndex}`].loadImageStack(series)
|
this.$refs[`dicomCanvas${canvasIndex}`].loadImageStack(series)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue