• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

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

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

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; }

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

看效果:

 

 

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

看效果:

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
c#开发地磅称重软件发布时间:2022-07-14
下一篇:
C#文件操作类大全发布时间:2022-07-14
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap