C#开发PACS医学影像处理系统(十五):Dicom影像交叉定位线算法

1.定位线概念:某个方位的影像在另一个方向的影像上的投影相交线,例如横断面(从头到脚的方向)在矢状面(从左手到右手)上的影像投影面交线。

举个例子:右边的是MR(核磁共振)的某一帧切片,这是从头开始扫描,扫描到眼睛这个位置,

而左边图像是从左手到右手的扫描切片,那么右边图像的位置就恰好在左边图像的眼睛的位置,用红线标出的位置则为定位线,一般用于医生参考病灶在矢状面、冠状面和横断面的具体方位。

2.检查设备示意图

在笛卡尔空间直角坐标系中,Y 右肩膀到左肩膀,X 后背到前胸,Z 足到头

3.算法流程

 4.代码实现:

创建图像结构

public FrameGeometry(DicomDataset image)
            : this(image.GetString(DicomTag.FrameOfReferenceUID),
                  image.GetValues<double>(DicomTag.ImagePositionPatient),
                  image.GetValues<double>(DicomTag.ImageOrientationPatient),
                  image.GetValues<double>(DicomTag.PixelSpacing),
                  image.GetSingleValue<int>(DicomTag.Columns),
                  image.GetSingleValue<int>(DicomTag.Rows))
        {
            // TODO: 
           FrameOfReferenceUID:图片UID
           ImagePositionPatient:病人方向
           ImageOrientationPatient:图片方向
           PixelSpacing:像素间距
           Columns:宽度
           Rows:高度

        }

判断是否符合定位条件:

 /// <summary>/// 判断是否可以画定位线
        /// </summary>
        /// <param name="sourceFrame">源图像结构</param>
        /// <param name="destinationFrame">目标图像结构</param>
        /// <returns></returns>
        public static bool CanDrawLocalizer(FrameGeometry sourceFrame, FrameGeometry destinationFrame)
        {
            // 检查图像结构
            if (sourceFrame == null) return false;
            if (destinationFrame == null) return false;

            // 如果两个帧中的任何一个不是空间坐标系,则无法定位
            if (sourceFrame.Orientation == FrameOrientation.None || destinationFrame.Orientation == FrameOrientation.None) return false;
            // 只有正交图像才能绘制,方向相同则退出
            if (sourceFrame.Orientation == destinationFrame.Orientation) return false;

            // 检查FrameOfReferenceUid
            if (string.IsNullOrEmpty(sourceFrame.FrameOfReferenceUid) || string.IsNullOrEmpty(destinationFrame.FrameOfReferenceUid)) return false;
            if (sourceFrame.FrameOfReferenceUid != destinationFrame.FrameOfReferenceUid) return false;

            return true;
        }

计算交线点:

/// <summary>
        ///回两个图像相交处公共像素线
        /// </summary>
        /// <param name="sourceFrame">源图像结构</param>
        /// <param name="destinationFrame">目标图像结构</param>
        /// <param name="startPoint">起点输出</param>
        /// <param name="endPoint">重点输出</param>
        /// <returns></returns>
        public static bool CalcualteIntersectionLocalizer(FrameGeometry sourceFrame, FrameGeometry destinationFrame, out Point2 startPoint, out Point2 endPoint)
        {
            double t; // 平面方程系数
            double nA, nB, nC, nD, nP;
            var lstProj = new List<Point3D>();

            // 初始化
            startPoint = Point2.Origin;
            endPoint = Point2.Origin;

            // 验证
            if (destinationFrame.DirectionNormal.IsZero)
                return false;

            nP = destinationFrame.DirectionNormal * destinationFrame.PointTopLeft;
            nA = destinationFrame.DirectionNormal * sourceFrame.PointTopLeft;
            nB = destinationFrame.DirectionNormal * sourceFrame.PointTopRight;
            nC = destinationFrame.DirectionNormal * sourceFrame.PointBottomRight;
            nD = destinationFrame.DirectionNormal * sourceFrame.PointBottomLeft;

            //  AB
            if (Math.Abs(nB - nA) > Constants.Epsilon)
            {
                t = (nP - nA) / (nB - nA);
                if (t > 0 && t <= 1)
                    lstProj.Add(sourceFrame.PointTopLeft + t * (sourceFrame.PointTopRight - sourceFrame.PointTopLeft));
            }

            // BC
            if (Math.Abs(nC - nB) > Constants.Epsilon)
            {
                t = (nP - nB) / (nC - nB);
                if (t > 0 && t <= 1)
                    lstProj.Add(sourceFrame.PointTopRight + t * (sourceFrame.PointBottomRight - sourceFrame.PointTopRight));
            }

            // CD
            if (Math.Abs(nD - nC) > Constants.Epsilon)
            {
                t = (nP - nC) / (nD - nC);
                if (t > 0 && t <= 1)
                    lstProj.Add(sourceFrame.PointBottomRight + t * (sourceFrame.PointBottomLeft - sourceFrame.PointBottomRight));
            }

            // DA
            if (Math.Abs(nA - nD) > Constants.Epsilon)
            {
                t = (nP - nD) / (nA - nD);
                if (t > 0 && t <= 1)
                    lstProj.Add(sourceFrame.PointBottomLeft + t * (sourceFrame.PointTopLeft - sourceFrame.PointBottomLeft));
            }

            if (lstProj.Count != 2)
                return false;

            // 从空间坐标系返回平面坐标系
            startPoint = destinationFrame.TransformPatientPointToImage(lstProj[0]);
            endPoint = destinationFrame.TransformPatientPointToImage(lstProj[1]);
            return true;
        }

得到坐标之后就可以利用绘图操作类(参考本系列教程之图形标记)来自己绘制定位线。

看效果:

对于较复杂的身体部位,也可以同时绘制定位线范围,来确定当前序列的定位范围,思路是先计算第一帧和最后一帧,用黄色虚线标出,再计算当前帧。

看效果:

 C#开发PACS、RIS、3D医学影像处理系统系列教程 目录整理:

菜鸟入门篇

C#开发PACS医学影像处理系统(一):开发背景和功能预览

C#开发PACS医学影像处理系统(二):界面布局之菜单栏

C#开发PACS医学影像处理系统(三):界面布局之工具栏

C#开发PACS医学影像处理系统(四):界面布局之状态栏

C#开发PACS医学影像处理系统(五):查询病人信息列表

C#开发PACS医学影像处理系统(六):加载Dicom影像

C#开发PACS医学影像处理系统(七):读取影像Dicom信息

C#开发PACS医学影像处理系统(八):单元格变换

C#开发PACS医学影像处理系统(九):序列控件与拖拽

C#开发PACS医学影像处理系统(十):Dicom影像下载策略与算法

C#开发PACS医学影像处理系统(十一):Dicom影像挂片协议

C#开发PACS医学影像处理系统(十二):绘图处理之图形标记

C#开发PACS医学影像处理系统(十三):绘图处理之病灶测量

C#开发PACS医学影像处理系统(十四):处理Dicom影像窗宽窗位

C#开发PACS医学影像处理系统(十五):Dicom影像交叉定位线算法

C#开发PACS医学影像处理系统(十六):2D处理之影像平移和缩放

C#开发PACS医学影像处理系统(十七):2D处理之影像旋转和翻转

C#开发PACS医学影像处理系统(十八):Dicom使用LUT色彩增强和反色

C#开发PACS医学影像处理系统(十九):Dicom影像放大镜

医学影像三维篇

C#开发PACS医学影像三维重建(一):使用VTK重建3D影像

C#开发PACS医学影像三维重建(二):使用VTK进行体绘制

C#开发PACS医学影像三维重建(三):纹理映射与颜色传输

C#开发PACS医学影像三维重建(四):3D网格平滑效果

C#开发PACS医学影像三维重建(五):基于梯度透明的组织漫游

C#开发PACS医学影像三维重建(六):三维光源与阴影效果

C#开发PACS医学影像三维重建(七):空间测量与标注

C#开发PACS医学影像三维重建(八):VR体绘制

C#开发PACS医学影像三维重建(九):MPR三视图切面重建

C#开发PACS医学影像三维重建(十):MIP最小密度投影

C#开发PACS医学影像三维重建(十一):CPR曲面重建

C#开发PACS医学影像三维重建(十二):VE虚拟内镜技术

C#开发PACS医学影像三维重建(十三):基于人体CT值从皮肤渐变到骨骼的梯度透明思路

C#开发PACS医学影像三维重建(十四):基于能量模型算法将曲面牙床展开至二维平面

熟手进阶篇

C#处理医学影像(一):基于Hessian矩阵的血管肺纹理骨骼增强对比

C#处理医学影像(二):基于Hessian矩阵的医学影像增强与窗宽窗位

C#处理医学影像(三):基于漫水边界自动选取病灶范围的实现思路

C#处理医学影像(四):基于Stitcher算法拼接人体全景脊柱骨骼影像

胶片打印:

C#开发医学影像胶片打印系统(一):万能花式布局的实现思路

C#开发医学影像胶片打印系统(二):胶片打印机通讯

C#开发医学影像胶片打印系统(三):Pacs二维功能在排版中的应用

登峰造极篇

C#开发基于Python人工智能的肺结节自动检测

C#开发基于Python人工智能的脊柱侧弯曲率算法

C#开发基于Python机器学习的医学影像骨骼仿真动画

C#开发基于Python机器学习的术后恢复模拟

C#开发基于U3D的VR眼镜设备虚拟人体三维重建

C#开发基于全息投影的裸眼3D医学影像显示技术

免费下载

免费下载使用本教程PACS软件

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值