当前位置: 首页 > article >正文

基于cornerstone3D的dicom影像浏览器 第二十一章 显示DICOM TAGS

系列文章目录

第一章 下载源码 运行cornerstone3D example
第二章 修改示例crosshairs的图像源
第三章 vite+vue3+cornerstonejs项目创建
第四章 加载本地文件夹中的dicom文件并归档
第五章 dicom文件生成png,显示检查栏,序列栏
第六章 stack viewport 显示dicom序列
第七章 在Displayer四个角落显示文字
第八章 在Displayer中显示图像方位
第九章 自动加载、清空显示、修改布局
第十章 显示标尺
第十一章 测量工具
第十二章 镜像、负像、旋转、伪彩、复位
第十三章 自定义垂直滚动条
第十四章 参考线、同步调窗、同步缩放、同步移动
第十五章 预设窗值
第十六章 工具栏svg按钮
第十七章 同步滚动
第十八章 自定义序列自动播放条
第十九章 显示overlay
第二十章 显示多帧图


文章目录

  • 系列文章目录
  • 前言
  • 一、读取标签
  • 二、显示标签列表
    • 1. 新建组件DcmTagsWnd.vue
    • 2. 调用流程
  • 总结


前言

读取Dicom文件中所有tags并显示到对话框中,提供查找功能。
效果如下:
在这里插入图片描述


一、读取标签

在image.js中增加读取标签列表的两个函数,readTagList读取普通tag, readTagSQ读取vr==SQ的序列标签

async readTagList() {let tagdata = [];const image = await imageLoader.loadAndCacheImage(this.imageId);let charset = image.data.string("x00080005") || "ISO_IR 100";let isUtf8 = charset.indexOf("ISO_IR 192") != -1;const tags2 = [];const tags = [];for (let key in image.data.elements) {const atag = {};const elem = image.data.elements[key];atag.tagid ="(" + key.substring(1, 5) + "," + key.substring(5) + ")";atag.tagid = atag.tagid.toUpperCase();atag.vr = elem.vr;atag.len = elem.length;atag.vm = image.data.numStringValues(key) || 0;atag.desc = DcmTagsDesc[key] || "UnkownTag";const isMeta = key.substring(1, 5) == "0002";if (key === "x7fe00010") {const pixLen = elem.length > 32 ? 32 : elem.length;atag.value = this.readNPixelAsHexString(image.data.byteArray,elem,pixLen);} else {if (atag.vr === "US" || atag.vr === "UL") {atag.value = image.data.uint16(key) + "";} else if (atag.vr === "FL") {atag.value = image.data.float(key) + "";} else if (atag.vr === "FD") {atag.value = image.data.double(key) + "";} else if (atag.vr === "SS") {atag.value = image.data.int16(key) + "";} else if (atag.vr === "SQ") {atag.value = "";if (isMeta) {tags2.push(atag);} else {tags.push(atag);}this.readTagSQ(isMeta ? tags2 : tags,elem.items,isUtf8,1);const endsq = {};endsq.tagid = "(FFFE,E0DD)";endsq.vr = "";endsq.vm = 0;endsq.len = 0;endsq.desc = DcmTagsDesc["xfffee0dd"];endsq.value = "";if (isMeta) {tags2.push(endsq);} else {tags.push(endsq);}} else {atag.value = readTagAsString(image.data.byteArray,elem.dataOffset,elem.length);if (atag.value) {atag.value = decodeChinese(atag.value, isUtf8);}}}//dicom tag第一个值不为02的放列表后面显示if (atag.vr !== "SQ") {if (isMeta) {tags2.push(atag);} else {tags.push(atag);}}}tagdata = [...tags2, ...tags];return tagdata;}readTagSQ(arr, items, isUtf8, level) {items.forEach(item => {const image = item.dataSet;const itemtag = {};itemtag.tagid ="(" +item.tag.substring(1, 5) +"," +item.tag.substring(5) +")";itemtag.tagid = getNSpace(level) + itemtag.tagid;itemtag.tagid = itemtag.tagid.toUpperCase();itemtag.len = item.length;itemtag.vr = "";itemtag.value = "";itemtag.vm = 0;itemtag.desc = DcmTagsDesc[item.tag] || "";arr.push(itemtag);for (let key in image.elements) {const elem = image.elements[key];const atag = {};atag.tagid ="(" +elem.tag.substring(1, 5) +"," +elem.tag.substring(5) +")";if (elem.tag === "xfffee00d")atag.tagid = getNSpace(level) + atag.tagid;else atag.tagid = getNSpace(level + 1) + atag.tagid;atag.tagid = atag.tagid.toUpperCase();atag.vr = elem.vr;atag.len = elem.length;atag.vm = image.numStringValues(elem.tag) | 0;atag.desc = DcmTagsDesc[elem.tag] || "UnkownTag";if (elem.tag === "x7fe00010") {const pixLen = elem.length > 32 ? 32 : elem.length;atag.value = this.readNPixelAsHexString(image.byteArray,elem,pixLen);} else {if (atag.vr === "US" || atag.vr === "UL") {atag.value = image.uint16(elem.tag) + "";} else if (atag.vr === "FL") {atag.value = image.float(elem.tag) + "";} else if (atag.vr === "FD") {atag.value = image.double(elem.tag) + "";} else if (atag.vr === "SS") {atag.value = image.int16(elem.tag) + "";} else if (atag.vr === "SQ") {atag.value = "";arr.push(atag);this.readTagSQ(arr, elem.items, isUtf8, level + 2);const endsq = {};endsq.tagid = "(FFFE,E0DD)";endsq.vr = "";endsq.vm = 0;endsq.len = 0;endsq.desc = DcmTagsDesc["xfffee0dd"];endsq.value = "";arr.push(endsq);} else {atag.value = readTagAsString(image.byteArray,elem.dataOffset,elem.length);if (atag.value) {atag.value = decodeChinese(atag.value, isUtf8);}}if (atag.vr !== "SQ") arr.push(atag);}}});}

二、显示标签列表

1. 新建组件DcmTagsWnd.vue

fullData 与 dcmtagData关联tag list数据

<script setup name="DcmTagsWnd">
import { ref, watch } from "vue";
import { debounce } from "@kitware/vtk.js/macros";const dialogVisible = ref(false);
const fullData = ref(null);
const dcmtagData = ref(null);
const findText = ref("");watch(findText, val => {if (val.length > 0) {const debouncedFilter = debounce(() => {const lval = val.toLowerCase();const newData = fullData.value.filter(item => {return (item.tagid.toLowerCase().includes(lval) ||item.desc.toLowerCase().includes(lval) ||item.value.toLowerCase().includes(lval));});dcmtagData.value = newData;}, 300);debouncedFilter();}
});const show = data => {fullData.value = data || [];dcmtagData.value = data || [];dialogVisible.value = true;
};defineExpose({ show });
</script><template><div class="dcmtag"><el-dialogtitle="DICOM TAGS"v-model="dialogVisible"width="820px"draggable><el-table :data="dcmtagData" border height="600px"><el-table-columnproperty="tagid"label="TagId"width="100":show-overflow-tooltip="true"></el-table-column><el-table-columnproperty="vr"label="VR"width="50"></el-table-column><el-table-columnproperty="vm"label="VM"width="50"></el-table-column><el-table-columnproperty="len"label="Length"width="80"></el-table-column><el-table-columnproperty="desc"label="Description"width="250":show-overflow-tooltip="true"></el-table-column><el-table-columnproperty="value"label="Value"width="290":show-overflow-tooltip="true"></el-table-column></el-table><el-inputv-model="findText"placeholder="Find Text..."clearablestyle="width: 300px; margin: 2px 6px"></el-input></el-dialog></div>
</template><style lang="scss" scoped>
.dcmtag {user-select: text;
}.finder {display: flex;.finder__label {width: 60px;}
}:deep(.el-dialog__header) {background: #eee;height: 40px;padding: 8px 8px;border: none;text-align: left;
}:deep(.el-dialog__title) {color: #444;
}:deep(.el-dialog) {padding: 0;
}:deep(.el-table__header .is-leaf) {background-color: white;color: #444;
}:deep(.el-table__cell) {background-color: white;color: #444;padding: 4px 0px;
}:deep(.el-table--enable-row-hover .el-table__body tr:hover > td) {background-color: lightblue;
}:deep(.el-table--border .el-table__cell:first-child .cell) {padding-left: 4px;
}
</style>

2. 调用流程

  • 工具栏上添加"DICOM标签"按钮,参考前面章节
  • DisplayerArea中添加DcmTagsWnd组件
  • 选中窗口,点击按钮
  • 读取tag list, 传入DcmTagsWnd并显示对话框

view2d.vue

async function OnToolbarAction(action) {switch (action.name) {case "openFolder":{const fileHandles = await openFolder();if (Array.isArray(fileHandles)) {fileHandles.forEach(fileHandle => {fileHandle.getFile().then(file => {archiveStore.archiveFile(file);});});} else {console.error("openFolder, fileHandles is not an array");}}break;...case "setWindow":displayArea.value.setViewportWindow(action.wl, action.ww);break;case "dcmtag":displayArea.value.showDcmTagsDialog();break;}
}

DisplayerArea.vue

import DcmTagsWnd from "./DcmTagsWnd.vue";
const dcmTagsWnd = ref(null);
const showDcmTagsDialog = async () => {// console.log("showDcmTagsWnd");if (selected.length>0) {const disp = dispRefs[selected[0]];const tagList = await disp.getTagList();// console.log("showDcmTagsWnd tagList:", tagList);dcmTagsWnd.value.show(tagList);}
}<template><div class="displayarea"><DcmTagsWnd ref="dcmTagsWnd" />...
</template>

总结

  1. 遍历dicom文件tag,获取tag list
  2. 对话框中显示tag list,并提供查找功能
http://www.lryc.cn/news/2385170.html

相关文章:

  • 【循环位运算——uint32,DP】
  • 贪心介绍 LeetCode 455.分发饼干 LeetCode 376. 摆动序列 LeetCode 53. 最大子序和
  • 算法学习笔记·数学·快速幂
  • Postgresql 数据库体系架构
  • [创业之路-377]:企业战略管理案例分析-战略制定/设计-市场洞察“五看”:看宏观之社会发展趋势:数字化、智能化、个性化的趋势对初创公司的战略机会
  • Vue框架1(vue搭建方式1,vue指令,vue实例生命周期)
  • 分布式系统核心技术全解析
  • skywalking 10.2 源码编译
  • C++ --- string
  • Android Studio 连接夜神模拟器 自动断开的问题
  • Python入门手册:Python中的数据结构类型
  • 《P3435 [POI 2006] OKR-Periods of Words》
  • C/C++---隐式显式转换
  • 巡礼中国西极·跨越昆仑天山 | 北斗卫星徽章护航昆仑科考
  • Vue常用自定义指令-积累的魅力【VUE】
  • LangChain4j第三篇: RAG的简单应用与实践
  • 机器学习第二十六讲:官方示例 → 跟着菜谱学做经典菜肴
  • 功能强大且易于使用的 JavaScript 音频库howler.js 和AI里如何同时文字跟音频构思想法
  • 品鉴JS的魅力之防抖与节流【JS】
  • 如何使用patch-package给npm包打补丁
  • maxkey单点登录系统
  • windows bat 在目录下(包括子目录)搜索批量指定文件名称复制到另一个文件夹内
  • Notepad++ 下载与安装教程(小白专属)
  • Spring Cloud Gateway 微服务网关实战指南
  • 微服务架构实战:Eureka服务注册发现与Ribbon负载均衡详解
  • 采用多维计算策略(分子动力学模拟+机器学习),显著提升 α-半乳糖苷酶热稳定性
  • 【java】小练习--零钱通
  • 旅游信息检索
  • 贝叶斯理论
  • Docker-mongodb