欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

VTK & OpenCV-读取DICOM图像返回它的像素矩阵

程序员文章站 2022-03-31 23:24:57
...

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

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

//
#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 <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类型返回
//这个就是使用VTK读取DICOM图像并将像素值转给OpenCV的Mat对象的程序,程序运行后,会传出一个Mat对象,和一个VTK的Reader对象(这个没有作用,只是可以保存下来,如果有操作需要VTK的时候才有用)。
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列的像素值
            }
        }
    }
}
//DICOM图像比较特殊,不能直接使用imshow()函数去可视化,需要进行简单的处理。分配到0-255
void showdicom(Mat I) {
    double maxx = 0, minn = 0;
    double *max = &maxx;
    double *min = &minn;
    /*
     * 函数void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const;
     */ 
    I.convertTo(I, CV_8UC1);
    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);
}
//

int main() {
    string filename = "../data/dicom/brain_001.dcm";
    Mat I1, G1;
    vtkSmartPointer<vtkDICOMImageReader> reader =
        vtkSmartPointer<vtkDICOMImageReader>::New();
    // 读入dicom图,使用OpenCV的Mat类型返回
    dicomread(filename, I1, reader);
    flip(I1, I1, 0);
    cout << I1.channels() << "  " << I1.size() << endl;
    cout << I1;
//DICOM图像比较特殊,像素值范围大,不能直接使用imshow()函数去可视化,需要进行简单的处理。量化一下
    showdicom(I1);
}
相关标签: VTK opencv