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