zoukankan      html  css  js  c++  java
  • C#开发PACS医学影像处理系统(十四):处理Dicom影像窗宽窗位

    概念解释(网络资料)

    窗宽:

    窗宽指CT图像所显示的CT 值范围。在此CT值范围内的组织结构按其密度高低从白到黑分为16 个灰阶以供观察对比。例如,窗宽选定为100 Hu ,则人眼可分辨的CT值为100 / 16 =6 . 25 Hu ,即2 种组织CT值相差在6 . 25Hu以上者即可为人眼所识别。因此,窗宽的宽窄直接影响图像的清晰度与对比度。如果使用窄的窗宽,则显示的CT 值范围小,每一灰阶代表的CT 值幅度小,对比度强,适于观察密度接近的组织结构(如脑组织)。反之,如果使用宽的窗宽,则显示的CT值范围大,每一灰阶代表的CT 值幅度大,则图像对比度差,但密度均匀,适于观察密度差别大的结构。

    窗位:
    窗位(窗中心)指窗宽范围内均值或中心值。比如一幅CT图像,窗宽为100Hu,窗位选在0Hu;则以窗位为中心(0Hu),向上包括+50Hu,向下包括-50Hu,凡是在这个100Hu 范围内的组织均可显示出来并为人眼所识别。凡是大于+50Hu 的组织均为白色;凡是小子-50Hu 的组织均为黑色,其密度差异无法显示。人眼只能识别土50Hu 范围内的CT 值,每一个灰阶的CT 值范围是100 / 16=6 . 25 Hu 。
     
    1.调窗
    在PACS影像中,常用的功能一般是调窗、作用范围和自定义调窗
    根据本系列文章中,在读取dicom影像时,可以获得dcm文件的窗宽窗位值:
    //实例化文件处理对象并打开文件
    DicomFile dicomFile = DicomFile.Open(@"C:1011.dcm");
    //获取dicom图像对象
    DicomImage dicomImage = new DicomImage(dicomFile.Dataset);
    //获取窗宽
    Console.WriteLine(dicomImage.WindowWidth);
    //获取窗位
    Console.WriteLine(dicomImage.WindowCenter);

    在鼠标操作上,按住鼠标左右移动是调整窗宽,上下移动是调整窗位,记录鼠标按下时的位置和拖动坐标差,并重新设置影像的窗宽窗位:

         //监听鼠标按下事件
            private void GridLine_MouseDown(object sender, MouseButtonEventArgs e)
            {try
                {
                    SelectedBox(true);
                    if (shapeManager.drawAction != DrawAction.None)
                    {
                        return;
                    }
                    //记录鼠标位置
                    isMouseDown = true;
                    StartPoint.X = e.GetPosition(GridLine).X;
                    StartPoint.Y = e.GetPosition(GridLine).Y;
    
                    if (DicomFile != null)
                    {
                        double? tagVal;
                        DicomFile.Dataset.TryGetValue(DicomTag.WindowCenter, 0, out tagVal);
    
                        if (tagVal != null)
                        {
                            //获取原始调窗
                            datasetWinC = DicomFile.Dataset.GetValue<double>(DicomTag.WindowCenter, 0);
                            datasetWinW = DicomFile.Dataset.GetValue<double>(DicomTag.WindowWidth, 0);
    
                            //设置最后一次调窗
                            lastWindowCenter = DicomImage.WindowCenter - datasetWinC;
                            lastWindowWidth = DicomImage.WindowWidth - datasetWinW;
                        }
                        else
                        {
                            lastWindowCenter = DicomImage.WindowCenter;
                            lastWindowWidth = DicomImage.WindowWidth;
                        }
                        mouseDownScaleX = st.ScaleX;
                        mouseDownScaleY = st.ScaleY;
    
                    }
                }
                catch (Exception ex)
                {
                    LogApi.WriteErrLog(ex);
                }
            }

    看效果:

    2.自定义调窗

    可以使用键值对或其他数据格式来保存和加载自定义窗宽窗位,常用参考值如下:

    1、胸部CT检查时,肺窗纵膈窗窗宽、窗位分别是:

    (1)肺窗WW1500—2000HU 、WL-450—-600HU

    (2)纵膈窗WW250—350HU、WL30—50HU

    2、骨窗、软组织窗窗宽、窗位

    (1)骨窗WW1000—1500HU、WL250—350HU

    (2)软组织窗WW300—500HU、WL40—60HU

    3、窗宽和窗位设定

    不同部位使用不同窗宽窗位,能较充分反映解剖内容和病灶影像表现,

    头颅:脑组织窗宽设定为80 Hu~100 Hu,窗位为30 Hu~40 Hu,

    垂体及蝶鞍区病变窗宽宜设在200 Hu~250 Hu,窗位45 Hu~50 Hu,

    脑出血患者可改变窗宽位80 Hu~140 Hu,窗位30 Hu~50 Hu,

    脑梗死患者常用窄窗60 Hu,能提高病灶的检出率,清楚显示梗死及软化灶,

    颌面部眼眶窗宽定为150 Hu~250 Hu,窗位30 Hu~40 Hu,

    观察骨骼时窗宽150 Hu~2 000 Hu,窗位400 Hu~450 Hu,

    喉颈部、鼻咽、咽喉部的窗宽和窗位常设在300 Hu~350 Hu和30 Hu~50 Hu,能满足该部位的解剖和病灶显示,

    胸部:常规胸部CT检查分别用纵隔窗及肺窗观察,纵隔窗可观察心脏、大血管的位置,

    纵隔内淋巴结的大小,纵隔内肿块及这些结构的比邻关系,设定纵隔窗可用窗宽300 Hu~500 Hu,窗位30 Hu~50 Hu

    根据此参考,我们可以设定一些默认的自定义调窗:

    3.调窗的用作范围

    根据之前的文章:C#开发PACS医学影像处理系统(八):单元格变换

    当作用范围是全部时,遍历所有单元格和容器:

     for (int i = 0; i < Main.Mdiview.Cells.Count; i++)
          for (int j = 0; j < Main.Mdiview.Cells[i].BoxList.Count; j++)

    当作用范围是序列时,只需遍历当前单元格容器:

     for (int i = 0; i < Cell.BoxList.Count; i++)

    当作用范围是图像时,直接设置图像:

    //调整窗位
    dicomImage.WindowCenter = 100;
    //调整窗宽
    dicomImage.WindowWidth = 100;

    部分代码:

          /// <summary>
            /// 变换窗宽窗位
            /// </summary>
            /// <param name="X"></param>
            /// <param name="startX"></param>
            /// <param name="Y"></param>
            /// <param name="startY"></param>
            public void WinImage(double X, double startX, double Y, double startY, double myWidth = -999, double myCenter = -999)
            {
                double cVal = Y - startY;
                double wVal = X - startX;
    
                if (myWidth != -999 && myCenter != -999)
                {
                    DicomImage.WindowCenter = myCenter;
                    DicomImage.WindowWidth = myWidth;
                }
                else
                {
                    DicomImage.WindowCenter = datasetWinC + lastWindowCenter + cVal;
                    DicomImage.WindowWidth = datasetWinW + lastWindowWidth + wVal;
                }
    
                ImageHandler.SetImageScale(DicomImage, PalImgInfo);
                UpDateTag();
    
                if (Main.WinRange == WindowRange.Series)
                {
                    #region -----作用范围:序列-----
    
                    for (int i = 0; i < Cell.BoxList.Count; i++)
                    {
                        if (Cell.BoxList[i] != this)
                        {
                            Cell.BoxList[i].WinImage(DicomImage.WindowWidth, DicomImage.WindowCenter);
                        }
                    }
    
                    #endregion
                }
                else if (Main.WinRange == WindowRange.All)
                {
                    #region -----作用范围:所有-----
    
                    for (int i = 0; i < Main.Mdiview.Cells.Count; i++)
                    {
                        for (int j = 0; j < Main.Mdiview.Cells[i].BoxList.Count; j++)
                        {
                            if (Main.Mdiview.Cells[i].BoxList[j] != this)
                            {
                                Main.Mdiview.Cells[i].BoxList[j].WinImage(DicomImage.WindowWidth, DicomImage.WindowCenter);
                                Main.Mdiview.Cells[i].MouseWindowCenter = DicomImage.WindowCenter;
                                Main.Mdiview.Cells[i].MouseWindowWidth = DicomImage.WindowWidth;
                            }
                        }
                    }
                    #endregion
                }
                else
                {
                    string key = Cell.studyInfo.CommonSeriesId + "|" + CurrentFrame;
                    string value = DicomImage.WindowWidth + "|" + DicomImage.WindowCenter;
                    if (PubVal.WinImageList.Keys.Contains(key))
                    {
                        PubVal.WinImageList[key] = value;
                    }
                    else
                    {
                        PubVal.WinImageList.Add(key, value);
                    }
                }
    
                Cell.MouseWindowCenter = DicomImage.WindowCenter;
                Cell.MouseWindowWidth = DicomImage.WindowWidth;
    
            }

    效果:

     

  • 相关阅读:
    Mysql有什么办法解决主备延迟的引起的过期读问题?
    jdk 8 交集 差集
    【立flag】_(:з」∠)_
    Linux基础01 虚拟机安装操作系统,网络类型(网口),网段, 分区,分配网络, KDUMP,网络配置, 快照, 克隆, Xshell优化, Linux历史
    oracle(enquences & latches )lock (oracle 锁大全)
    oracle 密码详解以及破解
    oracle 大表在线删除列操作(alter table table_name set unused )
    MacOs 使用 github 个人令牌(Personal access token)
    web网站在线安全扫描
    vue 实现快捷键录入功能
  • 原文地址:https://www.cnblogs.com/Uncle-Joker/p/13683841.html
Copyright © 2011-2022 走看看