• 关于医学图像处理中钙化积分的计算


    前言

    最近在做一个医学图像处理的项目,项目的内容就是在拉直的血管上面找到钙化的部分,并且计算出钙化积分。

    效果图如下所示:  

    第一章   医学背景知识介绍

    1.1 冠脉动脉钙化以及钙化积分定义

          冠状动脉钙化(CAC)的定性检测根据病变大小超过某一面积或体积阈值、密度超过规定的CT值阈值即可区分冠状动脉斑块内的病变是否为钙化。冠状动脉钙化积分(CACS)中传统的积分法AS定义面积阈值为1 mm2、CT值阈值为130 Hu。Detrano等使用8.16mm3的体积作为钙化灶大小的阈值。质量积分[10]定义面积阈值为连续的3个像素、CT值阈值为130 Hu。Nelson等[11]所使用的面积阈值为4个紧邻的像素,CT值阈值为130 Hu。另有研究者认为[12]不应使用某一固定的CT值作为病灶的密度阈值,因为同一密度的物体在不同CT机上的CT值可能有差异,故推荐使用一个固定的含钙浓度值(100 mg/cc)作为阈值。然而Glodny等[13]却尝试在CCTA图像中将冠状动脉上CT值大于600 Hu的像素分离出来作为钙化灶来研究,这种方法虽有偏颇,会明显低估钙化斑块负荷,但其结果却和常规CACS有高度线性相关性,甚至认为该方法可用于替代常规CACS以避免CACS扫描导致的电离辐射,这一观点尚待进一步的考证。

         Agatston等[2]首次使用了CACS对冠状动脉钙化斑块进行了定量分析,称之为Agatston 积分(Agatston Score, AS),
    AS= Σ (CT值 × 面积 × 权重系数)。
    CT值越高,权重系数越大,具体如下:130~199 Hu为1,200~299 HU为2,300~399 Hu为3,等于或大于400 Hu为4。
    1998年Callister等[14]报道了CAC的容积积分(Volume Score,VS)的定量分析。VS等于所有钙化斑块的容积之和。VS积分法所计算的是钙化的体积,而与钙化灶的密度变化没有对应关系。
    2005年Nelson等[11]使用了质量积分(Mass Score,MS)进行CAC的定量测量。MS的检测相对复杂,该方法须使用羟磷灰石钙校准体模,此体模由数个含钙浓度不同的模块组成,且浓度已知。体模与受检者须同时进行扫描。通过测量各个模块的CT值便可确定CT值与含钙浓度的计算关系,即:

    体模CT值 = 斜率 × 体模含钙浓度 + 截距。

    测出各个模块的CT值,可计算出斜率和截距。然后测量冠状动脉钙化斑块的CT值,根据上述关系计算出钙化斑块的含钙浓度,即:

    钙化斑块的含钙浓度 = (钙化斑块平均CT值-截距) ÷ 斜率。

    最后通过软件计算出冠状动脉全部钙化斑块的质量积分,即:

    MS = ∑(钙化灶的含钙浓度 × 容积)。

    AS是较客观的CAC量化分析方法,早己受到了影像界的认可,临床应用广泛,一直是传统的钙化斑块定量分析参数,但此方法的重复性不高,使病人间的对照及随访观察结果可信度下降。VS的重复性与AS相比有所改善,可用于高危人群随访及冠心病人治疗后复查。VS主要缺点是由于受部分容积效应的影响,另一方面VS没有考虑钙化斑块的CT值,而CT值的高低可能代表了斑块的演变阶段,因此可能存在一定的片面性,而且此方法的重复性仍有不足。由于每位患者的含钙浓度均是在体模校准的基础上获得,不受设备、扫描协议或患者个体差异的影响,其结果具有可比性,因而MS有良好的可重复性和准确性。在扫描协议标准化后,多中心的体模研究[8]使用不同生产厂商的CT机、不同机型的CT机进行CACS测量,结果为AS、VS与MS的变异系数分别为7.9%、4.0%、2.8%, MS具有最高的重复性和准确性,这与绝大部分研究结果一致。MS是国际心脏CT标准化协会物理工作组(the Physics Task Group ofthe International Consortium on Standardization in Cardiac CT)推荐的钙化定量分析方法[12]

    1.2窗宽、窗位、CT值

          人体组织CT值的范围为-1000到+1000共2000个分度,人眼不能分辨这样微小灰度的差别,仅能分辨16个灰阶。为了提高组织结构细节的显示, 能分辨CT值差别小的两种组织,操作人员可以根据诊断需要调节图像的对比度和亮度,这种调节技术称为窗技术-窗宽、窗位的选择。

          窗宽是指显示图像时所选用的CT值范围,在此范围内的组织结构按其密度高低从白到黑分为16个等级(灰阶)。如窗宽为160Hu,则可分辨的CT值为160/16=10Hu,即两种组织CT值的差别在10Hu以上者即可分辨出来。 由此可见窗宽的宽窄直接影响图像的对比度;窄窗宽显示的CT值范围小,每级灰阶代表的CT值幅度小,因而对比度强,可分辨密度较接近的组织或结构,如检查脑组织宜选用窄的窗宽;反之,窗宽加宽则每级灰阶代表的

    CT值幅度增大,对比度差,适于分辨密度差别大的结构如肺、骨质。窗位是指窗宽上、下限CT值的平均数。因为不同组织的CT值不同,欲观察其细微结构最好选择该组织的CT值为中心进行扫描,这个中心即为窗位。窗位的高低影响图像的亮度:窗位低图像亮度高呈白色;窗位高图像亮度低呈黑色,但在实际操作中尚须兼顾其它结

    构选用适当的窗位。总之,如要获得较清晰且能满足诊断要求的CT图像,必须选用合适的窗宽、窗位,否则

    图像不清楚,还往往难以达到诊断要求,降低了CT扫描的诊断效能。

    正常人体组织的CT值:

    类别
    CT值(HU)
    0±10
    脑脊液
    3-8
    血浆
    3-14
    水肿
    7-17
    脑白质
    25-32
    脑灰质
    30-40
    血液
    13-32
    血块
    64-84
    肝脏
    50-70
    脾脏
    50-65
    胰腺
    45-55
    肾脏
    40-50
    肌肉
    40-80
    胆囊
    10-30
    脂肪
    -20~-80
    钙化
    80-300
    空气-200HU以上
    骨骼+400以上

         窗宽,窗位,CT值之间的数量关系:通俗的说:窗位是窗宽的中位数数值,窗宽是范围,比如窗宽250,窗位50,CT值范围是-75~175HU,CT值的范围的中位数必须是50,而范围则是250。换算成公式的话如下:

     CT值的下限x = L-W/2,上限y = L+W/2;
    其中,L代表窗位的数值,W代表窗宽数值。
       
     第二章  算法设计
    2.1待续
     
    第三章  部分代码
    3.1vtk to OpenCV
    /*****************************************************/
    /*
    @function name:vtk2ipl
    @function:vtk格式图片转化到opencv格式
    @parameters
    srcDataVtk,sliceOrder:输入,srcDataVtk是vtkImageData格式体数据,sliceOrder是要抽取的体数据的slice编号
    dstDataMat :输出,dstDataMat 是opencv格式图像
    @result:
    @Notes:
    */
    /*****************************************************/
    
    
    void calScore::vtk2ipl(vtkImageData *srcDataVtk,Mat &dstDataMat,int sliceOrder)
    {
        vtkImageShiftScale* shiftScale = vtkImageShiftScale::New();
        shiftScale->SetInput(srcDataVtk);
        shiftScale->SetShift(-(800 - 0.5*1680));//800level,1680windows 这里
        shiftScale->SetScale(255.0/1680);
        shiftScale->SetOutputScalarTypeToUnsignedChar();
        shiftScale->ClampOverflowOn();
        shiftScale->Update();
    
        if (c_mode_XYZ =="XZ")//xz平面
        {
            cv::Mat image(dims[0], dims[2], CV_8UC1);
    
            for (int i=0; i<dims[0]; ++i) 
            {
                for (int j=0; j<dims[2]; ++j) 
                {
                    image.at<unsigned char>(cv::Point(j,i)) = 
                        *static_cast<unsigned char*>(shiftScale->GetOutput()->GetScalarPointer(i,sliceOrder,j));
                }
            }
            imwrite("D:\cvimg.bmp",image);
            image.copyTo(dstDataMat);
        }
    
        if (c_mode_XYZ =="YZ")//yz平面
        {
            cv::Mat image(dims[1], dims[2], CV_8UC1);
    
            for (int i=0; i<dims[1]; ++i) 
            {
                for (int j=0; j<dims[2]; ++j) 
                {
                    image.at<unsigned char>(cv::Point(j,i)) = 
                        *static_cast<unsigned char*>(shiftScale->GetOutput()->GetScalarPointer(sliceOrder,i,j));
                }
            }
            imwrite("D:\cvimg.bmp",image);
            image.copyTo(dstDataMat);
        }
    
        if (c_mode_XYZ =="XY")//xy平面
        {
            cv::Mat image(dims[0], dims[1], CV_8UC1);
    
            for (int i=0; i<dims[0]; ++i) 
            {
                for (int j=0; j<dims[1]; ++j) 
                {
                    image.at<unsigned char>(cv::Point(j,i)) = 
                    *static_cast<unsigned char*>(shiftScale->GetOutput()->GetScalarPointer(i,j,sliceOrder));
                    
                }
            }
            imwrite("D:\cvimg.bmp",image);
            image.copyTo(dstDataMat);
        }
        
        //free
        shiftScale->Delete();
    }

     3.2 OpenCV to VTK

     1 /*****************************************************/
     2      /*
     3      @function name:ipl2vtk
     4      @function:opencv格式图片转化到vtk格式
     5      @parameters
     6      _src:输入,-src 是OpenCV数据
     7      _dest :输出,_dest 是vtk格式图像
     8      @result:
     9      @Notes:
    10      */
    11     /*****************************************************/
    12 void calScore::ipl2vtk(IplImage* _src, vtkImageData* _dest)
    13 {
    14     vtkImageImport *importer = vtkImageImport::New();
    15     if ( _dest )
    16     {
    17         importer->SetOutput( _dest );
    18     }
    19     importer->SetDataSpacing( 1, 1, 1 );
    20     importer->SetDataOrigin( 0, 0, 0 );
    21     importer->SetWholeExtent(  0, _src->width-1, 0, _src->height-1, 0, _src->nChannels-1 );
    22     importer->SetDataExtentToWholeExtent();
    23     importer->SetDataScalarTypeToUnsignedChar();
    24     importer->SetNumberOfScalarComponents( _src->nChannels );
    25     importer->SetImportVoidPointer( _src->imageData );
    26     importer->Update();
    27 
    28     //free
    29     importer->Delete();
    30 
    31 }

    3.3 抽取slice

    /*****************************************************/
         /*
         @function name:extractSlice
         @function:抽取slice
         @parameters
         _srcvtk,sliceOrder:输入,_srcvtk是vtkImageData格式体数据,sliceOrder是要抽取的体数据的slice编号
         @result:返回抽取的slice数据,数据格式是vtkImageData
         @Notes:
         */
        /*****************************************************/
    vtkImageData *calScore::extractSlice(vtkImageData *_srcvtk,int sliceOrder)
    {
        _srcvtk = vtkImageData::New();
        _srcvtk->SetDimensions(imageData->GetDimensions());
        _srcvtk->SetScalarTypeToDouble();
        _srcvtk->SetNumberOfScalarComponents(4);
        _srcvtk->AllocateScalars();
        _srcvtk->DeepCopy(imageData);
        _srcvtk->Update();
        
    
        vtkExtractVOI*extractVOI = vtkExtractVOI::New();
        //extractVOI->SetInput(_srcvtk);
        extractVOI->SetInput(imageData);
    
        if (c_mode_XYZ =="XZ")//xz平面
        {
            extractVOI->SetVOI(0,dims[0],sliceOrder,sliceOrder,0,dims[2]);
        }
    
        if (c_mode_XYZ =="YZ")//yz平面
        {
            extractVOI->SetVOI(sliceOrder,sliceOrder,0,dims[1],0,dims[2]);
        }
    
        if (c_mode_XYZ =="XY")//xy平面
        {
            extractVOI->SetVOI(0,dims[0],0,dims[1],sliceOrder,sliceOrder);
        }
        
        extractVOI->Update();
    
        //vtkImageData *imgData2D = vtkImageData::New();
        //imgData2D->DeepCopy(extractVOI->GetOutput());
        
        //return imgData2D;
        return extractVOI->GetOutput();
    }
    第四章 总结
    4.1待续
     
     
     
     
             1.2节 http://blog.sina.com.cn/s/blog_4c88d09a0100k8b1.html   http://www.dxy.cn/bbs/thread/20979764#20979764
  • 相关阅读:
    数据可视化之DAX篇(二十)Think in DAX 之报表自动化实践
    数据可视化之DAX篇(十九)值得你深入了解的函数:SUMMARIZE
    数据可视化之DAX篇(十八)收藏 | DAX代码格式指南
    数据可视化之DAX篇(十七)Power BI表格总计行错误的终极解决方案
    atomic_compare_exchange_weak_explicit (Atomic operations) – C 中文开发手册
    Spring Boot的How-to指南:嵌入式Web服务器
    C# 文本文件的读写
    CSS outline 属性
    operator (Numeric & Mathematical) – Python 中文开发手册
    HTML DOM Style animationDirection 属性
  • 原文地址:https://www.cnblogs.com/mothe123/p/4481626.html
Copyright © 2020-2023  润新知