读取并可视化DICOM图像(VTK & OpenCV)


本人最近刚完成一个项目的一部分程序的编写。项目主要工作是将CT实时显示,而CT成像较为缓慢,因此首先的步骤就是将CT图转为超声图。简单来说,本人完成的工作就是将CT图转为超声图,并保存下来

工作思路

整个工作,最难的就是CT图的正确读取。本人处理的CT图的格式是DICOM格式,这个用OpenCV不能直接读取,我采用了VTK进行读取,然后用OpenCV处理的思路(当然网上也有人说可以直接用ITK读取并处理,只是我不熟悉ITK,所以没有用它)。

DICOM图像的读取

其实读取DICOM图像不难,主要的要注意在使用VTK读取的时候,要记得转换数据类型,要使用imagecast转到double(或float)型,这样像素值出来的才是正确的,这样在转到OpenCV上,就可以使用OpenCV显示并处理,最后写入(保存)。

使用OpenCV的原因

因为OpenCV简单,处理图像起来比VTK简单很多,显示图片也不需要理解VTK中的管线等概念。

程序实现

实现平台:Win10,C++,Microsoft Visual Studio 2010

VTK5.6,OpenCV 2.4.10

#include <iostream>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <vtkSmartPointer.h>
#include <vtkImageViewer2.h>
#include <vtkImageCast.h>
#include <vtkDICOMImageReader.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkImageData.h>
#include <vtkCoordinate.h>

using namespace cv;
using namespace std;

// 读入一个CT图,返回它的像素矩阵,使用OpenCV的Mat类型返回
void dicomread(string inputFilename, Mat &img,vtkSmartPointer<vtkDICOMImageReader> &reader)
{
    img.create(512,512,CV_32SC1); 

    vtkSmartPointer<vtkImageCast> imageCast = 
        vtkSmartPointer<vtkImageCast>::New();

    reader->SetFileName(inputFilename.c_str());

    reader->Update();

    imageCast->SetInputConnection(reader->GetOutputPort());
    imageCast->SetOutputScalarTypeToInt();
    imageCast->Update();

    // 图像的基本信息
    int dims[3];
    reader->GetOutput()->GetDimensions(dims);

    //图像的像素值
    for(int k=0;k<dims[2];k++)
    {
        for(int j=0;j<dims[1];j++)
        {
            for(int i=0;i<dims[0];i++)
            {
                int* pixel = 
                    (int*)(imageCast->GetOutput()->GetScalarPointer(i,j,k)); // 第i列第j行的像素值
                img.at<int>(j,i) = int(*pixel); // 第j行第i列的像素值
            }
        }
    }
}

这个就是使用VTK读取DICOM图像并将像素值转给OpenCV的Mat对象的程序,程序运行后,会传出一个Mat对象,和一个VTK的Reader对象(这个没有作用,只是可以保存下来,如果有操作需要VTK的时候才有用)。然后,我显示了一下得到的Mat对象的信息。

#include <iostream>
#include <string>
#include <vector>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <vtkSmartPointer.h>
#include <vtkImageViewer2.h>
#include <vtkDICOMImageReader.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>

using namespace std;
using namespace cv;

extern void dicomread(string inputFilename, Mat &img,vtkSmartPointer<vtkDICOMImageReader> &reader);

int main()
{
    string filename = "D:\\CT\\CT000895";
    Mat I1,G1;

    vtkSmartPointer<vtkDICOMImageReader> reader = 
        vtkSmartPointer<vtkDICOMImageReader>::New();
    // 读入dicom图
    dicomread(filename,I1,reader);
    flip(I1,I1,0);
    cout << I1.channels() << "  " << I1.size() << endl;
}

运行结果:

结果显示:图像是单信道的,大小为512×512

可视化DICOM图像

DICOM图像比较特殊,不能直接使用imshow()函数去可视化,需要进行简单的处理。直接上程序,

void showdicom(Mat I)
{
    double maxx=0,minn=0;
    double *max = &maxx;
    double *min = &minn;
    I.convertTo(I,CV_64FC1);
    minMaxIdx(I,min,max);
    for(int i=0;i<I.rows;i++)
    {
        for(int j=0;j<I.cols;j++)
        {
            I.at<double>(i,j) = 255*(I.at<double>(i,j)-minn)*1/(maxx-minn);
        }
    }

    imshow("DICOM Image",I);
    waitKey(0);
}

运行测试结果:

至此,成功读取并可视化DICOM图像。

项目文件:http://download.csdn.net/detail/louishao/9876308

猜你喜欢

转载自blog.csdn.net/louishao/article/details/73528985
今日推荐