影像云胶片:Dicom纯js的三维重建影像阅片器

**影像云胶片主要:**通过浏览器浏览Dicom影像阅片,通过多终端设备(如电脑、平板、手机),为医生、患者及其他授权人员提供随时随地的影像调阅功能,打破时间和空间限制。同时,支持影像数据在不同医疗机构之间的安全共享,促进医疗协作与远程会诊的开展。主要功能:

  1. 支持标准DIcom影像的2D浏览,预设窗位,伪彩,序列间,序列内多种布局方式。
  2. 影像处理,提供影像翻图、缩放、移动、透镜、反相、旋转、截图等操作
  3. 影像测量,提供箭头、直线、十字架、角度、Cobb、心胸比、椭圆、矩形、勾画,橡皮擦、CT值等数据的测量
  4. 支持影像的三维重建,包括多平面重建,容积漫游技术(VR)、最大/小密度投影等功能
  5. 支持影像胶片打印功能,包括DR,CT等胶片自定义布局打印
  6. 支持平板,手机等移动设备的影像浏览

总体架构:BS(浏览器/服务器)架构

  • 前端:基于HTML5、WebGL技术开发,无需安装插件,支持PC浏览器、手机H5、微信小程序、支付宝小程序等多种终端。

  • 后端:后端居于fo-dicom组件进行开发,对dicom文件访问授权服务,访问MD5签名验证等身份验证。

核心技术栈

  • 影像渲染引擎 :使用 VTK.js 等开源框架,实现基于WebGL的高性能二维、三维影像渲染。

  • DICOM服务:自研或使用开源组件(如fo-dicom)实现DICOM文件的接收(C-Store)、查询(C-Find)、检索(C-Move)等服务。

主要代码示例

1:前端采用有vue3+element-ui进行开发,检查屏幕大小,以便适应不同的屏幕

复制代码
<script setup>
import LeftSeriesMobile from './views/LeftSeriesMobile.vue'
import CenterImage from './views/CenterImage.vue'
import RightToolMobile from './views/RightToolMobile.vue'
import { ElMessageBox } from 'element-plus'

// 注册resize事件监听器 调整laytou大小
window.addEventListener('resize', function (evt) {
  if (window.innerWidth > 768) {
    ElMessageBox.alert("系统检测到你在阅片期间对浏览器进行了缩放。为防止图像显示及测量工作不精确,强烈建议您重新打开影像!");
  }
});

</script>

<template>
  <div class="divRightMb">
    <RightToolMobile />
  </div>
  <div class="divCenterMb" id="divCenter">
    <CenterImage />
  </div>
  <div class="divLeftMb">
    <LeftSeriesMobile />
  </div>
</template>

<style scoped></style>

最终在PC端和手机端效果图如下:

2:使用VTK.js 等开源框架,实现基于WebGL的高性能二维、三维影像渲染。

复制代码
//初始化一个视窗
function ViewGridChange_LoadDicom_OneView(layout, element, showSeries) {
  //注册事件
  element.addEventListener(IMAGE_RENDERED, IMAGE_RENDERED_CallBack);

  layout.ShowSeries = showSeries;//当前窗体显示的序列对象
  element.ShowSeries = showSeries;//当前窗体显示的序列对象
  let viewport;
  if (showSeries.SeriesItemType == 1) {
    viewport = {
      viewportId: layout.viewportId,
      type: showSeries.viewType,
      element: element
    }
    element.addEventListener(STACK_NEW_IMAGE, STACK_NEW_IMAGE_CallBack);
  } else {
    viewport = {
      viewportId: layout.viewportId,
      type: showSeries.viewType,
      element: element,
      defaultOptions: {
        orientation: showSeries.orientation
      },
    }
    element.addEventListener(VOLUME_NEW_IMAGE, VOLUME_NEW_IMAGE_CallBack);
  }
  return viewport;
}

​3:实现三维十字准线工具的功能

复制代码
function InitCrosshairsTool(renderingEngineId, toolGroupObj, viewLayoutArray) {
    if (!VailSign()) return;

    _renderingEngineId = renderingEngineId;
    viewportColors = new Array();
    viewportReferenceLineControllable = new Array();
    viewportReferenceLineDraggableRotatable = new Array();
    viewportReferenceLineSlabThicknessControlsOn = new Array();

    for (let i = 0; i < viewLayoutArray.length; i++) {
        const curLayout = viewLayoutArray[i];
        if (!curLayout.ShowSeries) { continue; }
        if (curLayout.IsCrosshairs != true) { continue; }
        let isAdd = false;
        if (curLayout.ShowSeries.SeriesItemType == 2) {
            viewportColors[curLayout.viewportId] = 'rgb(200, 0, 0)';
            isAdd = true;
        } else if (curLayout.ShowSeries.SeriesItemType == 3) {
            viewportColors[curLayout.viewportId] = 'rgb(200, 200, 0)';
            isAdd = true;
        } else if (curLayout.ShowSeries.SeriesItemType == 4) {
            viewportColors[curLayout.viewportId] = 'rgb(0, 200, 0)';
            isAdd = true;
        }

        if (isAdd == true) {
            viewportReferenceLineControllable.push(curLayout.viewportId);
            viewportReferenceLineDraggableRotatable.push(curLayout.viewportId);
            viewportReferenceLineSlabThicknessControlsOn.push(curLayout.viewportId);
        }
    }
    if (toolGroupObjIsAdd == false) {
        cornerstoneTools.addTool(CrosshairsTool);

        const isMobile = window.matchMedia('(any-pointer:coarse)').matches;
        toolGroupObj.toolGroup.addTool(CrosshairsTool.toolName, {
            getReferenceLineColor,
            getReferenceLineControllable,
            getReferenceLineDraggableRotatable,
            getReferenceLineSlabThicknessControlsOn,
            mobile: {
                enabled: isMobile,
                opacity: 0.8,
                handleRadius: 9,
            },
        });
        toolGroupObjIsAdd = true;
    }
    if (viewportReferenceLineControllable.length > 1) {
        //toolGroupObj.toolGroup.setToolPassive(CrosshairsTool.toolName);//激活 十字准线
        toolGroupObj.SetMouseLeftTool(CrosshairsTool.toolName);//初始化默认激活左键为 3D探针
    }
}

​三维重建效果如图所示:

4:胶片打印布局设置相关代码

复制代码
//设置中间图像大小
let curGolb_PaperSize = "";//当前纸张大小
let curGolb_Direction = "";//当前方向
let curGolb_ShowScale = "1";//当前显示比例
function CenterSetImageSize(paperSize, direction, showScale, isPrint) {
    SetImageSizeisPrint = isPrint;
    if (isEmpty(paperSize)) paperSize = curGolb_PaperSize;
    if (isEmpty(direction)) direction = curGolb_Direction;
    if (isEmpty(showScale)) showScale = curGolb_ShowScale;
    if (curGolb_PaperSize == paperSize && curGolb_Direction == direction && curGolb_ShowScale == showScale) {
        return;
    }
    curGolb_PaperSize = paperSize;
    curGolb_Direction = direction;
    curGolb_ShowScale = showScale;

    //根据纸张大写设置图像大小
    let paperObj = null;
    for (let i = 0; i < PaperSizeArys.length; i++) {
        const item = PaperSizeArys[i];
        if (item.value == paperSize) {
            paperObj = item;
            break;
        }
    }
    if (!paperObj) return;

    //设置图像大小
    let imgWidth = 0;
    let imgHeight = 0;
    if (direction == "0") {//横向
        imgWidth = paperObj.ImgHeight;
        imgHeight = paperObj.ImgWidth;
    } else {//纵向
        imgWidth = paperObj.ImgWidth;
        imgHeight = paperObj.ImgHeight;
    }
    let imgWidthPx = imgWidth * 96;
    let imgHeightPx = imgHeight * 96;

    let scaleFloat = 1;
    if (showScale == "-2") {//自适应宽高
        const rect = divImgElemet.parentElement.getBoundingClientRect();
        //如果宽或者高 任意一个大于了外层容器 则进行缩放
        if (imgWidthPx > rect.width || imgHeightPx > rect.height) {
            //如果宽超出的范围更大,则以宽为基准进行缩放
            if (imgWidthPx - rect.width >= imgHeightPx - rect.height) {
                scaleFloat = rect.width / imgWidthPx;
            } else {
                //以高位基准进行缩放
                scaleFloat = rect.height / imgHeightPx;
            }
            scaleFloat = scaleFloat * 0.98;//自适应时设置图像显示比例98%,防止出现滚动条
        }
    } else if (showScale == "-1") {//自适应宽
        const rect = divImgElemet.parentElement.getBoundingClientRect();
        //如果宽或者高 任意一个大于了外层容器 则进行缩放
        if (imgWidthPx > rect.width) {
            //如果宽超出的范围更大,则以宽为基准进行缩放            
            scaleFloat = rect.width / imgWidthPx * 0.98;//自适应时设置图像显示比例98%,防止出现滚动条
        }
    } else {
        scaleFloat = parseFloat(showScale);
    }
    imgWidth = numToFixed(imgWidth * scaleFloat, 0) + "in";
    imgHeight = numToFixed(imgHeight * scaleFloat, 0) + "in";

    if (imgWidth == divImgElemet.style.width && imgHeight == divImgElemet.style.height) {
        //图像大小不变,如果是打印则直接执行打印
        if (SetImageSizeisPrint == true) {
            PrintCurrentPage(false);
        }
    } else {
        divImgElemet.style.width = imgWidth;
        divImgElemet.style.height = imgHeight;

        //设置图像上字体大小
        let dfontSieze = 11;
        if (!isEmpty(PrintConfigObj.FontSize)) {
            dfontSieze = parseInt(PrintConfigObj.FontSize);
        }
        const setFontSize = numToFixed(dfontSieze * scaleFloat, 2) + "px";//标注字体为11px,乘以缩放比例
        divImgElemet.style.fontSize = setFontSize;

        //获取元素像素大小
        document.querySelector("#spShowImgSizePx").innerHTML = divImgElemet.scrollWidth + "×" + divImgElemet.scrollHeight;
    }
}

胶片打印布局效果如图

技术交流沟通联系QQ:343798739;469116292

相关推荐
AndrewHZ10 天前
【图像处理基石】通过立体视觉重建建筑高度:原理、实操与代码实现
图像处理·人工智能·计算机视觉·智慧城市·三维重建·立体视觉·1024程序员节
人类发明了工具25 天前
【三维重建-对极几何】极线约束(Epipolar Constraint)
图像处理·数码相机·三维重建
-dzk-1 个月前
【3DGS复现】Autodl服务器复现3DGS《简单快速》《一次成功》《新手练习复现必备》
运维·服务器·python·计算机视觉·3d·三维重建·三维
杀生丸学AI1 个月前
【无标题】SceneSplat:基于视觉-语言预训练的3DGS场景理解
3d·aigc·slam·语义分割·三维重建·视觉大模型·空间智能
点云SLAM2 个月前
结构光三维重建原理详解(1)
人工智能·数码相机·计算机视觉·三维重建·结构光重建·gray 编码·标定校正
AndrewHZ2 个月前
【3D算法技术】blender中,在曲面上如何进行贴图?
算法·3d·blender·贴图·三维建模·三维重建·pcg
杀生丸学AI2 个月前
【三维重建】3R-GS:优化相机位姿的3DGS最佳实践
人工智能·3d·aigc·三维重建·视觉大模型·高斯泼溅
逐云者1232 个月前
论文介绍:“DUSt3R”,让 3D 视觉从“繁琐”走向“直观”
人工智能·transformer·vr·三维重建·ar、
AndrewHZ2 个月前
【3D算法技术入门】如何基于建筑图片重建三维数字资产?
图像处理·算法·3d·三维重建·colmap·点云处理·立体匹配