视频教程:一种简单的Dicom图像显示和保存的方法(利用dcmtk库和opencv库)
Git: https://github.com/JasonLiThirty/Dicom
opencv的下载
- 官网:https://opencv.org/releases/,下载最新版本4.3.0
- 安装即解压:
Dicom_Module工程配置opencv库
- 配置系统的环境变量Path:把之前解压(安装)好的opencv路径下的x64的bin路径添加到Path系统环境变量中,重启。
- 在Dicom_Module工程配置中加入opencv的include路径和lib路径。
- 在工程配置的linker->input里加入opencv的依赖lib,Debug配置opencv_world430d.lib,Relase配置opencv_world430.lib,这两个lib文件在opencv\build\x64\vc14\lib下。
- 将opencv\build\x64\vc14\bin目录下的opencv_world430.dll和opencv_world430d.dll拷贝到工程的输出目录下。
Dicom_Module工程配置dcmimgle和dcmimage库
- 在工程配置的linker->input里加入dcmimgle和dcmimage的依赖lib
-
将最先编译出的DCMTK类包中bin目录下的dcmimgle.dll和dcmimage.dll拷贝到工程的输出目录下。
Dicom_Module工程里编写所需类和函数
接口类DicomIF
- 新增显示图像和保存图像为BMP的接口
1 2 3 4 5 6 7 8 | class __declspec(dllexport) IDicom { public: ... virtual bool ShowImage(std::string filePath, Image_Pattern pattern = ImagePattern_Normal, signed int degree = 0) = 0; virtual bool SavetoBMP(std::string filePath, Image_Pattern pattern = ImagePattern_Normal, signed int degree = 0) = 0; ... } |
实现类DicomProcessor
- 新增显示图像和保存图像为BMP的实现(头文件包含dcmimage.h)
1 2 3 | #include "dcmtk/dcmimgle/dcmimage.h" bool ShowImage(std::string filePath, Image_Pattern pattern = ImagePattern_Normal, signed int degree = 0); bool SavetoBMP(std::string filePath, Image_Pattern pattern = ImagePattern_Normal, signed int degree = 0); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | bool DicomProcessor::ShowImage(std::string filePath, Image_Pattern pattern, signed int degree) { if (!Read(filePath)) { std::cout << "Read Dicom File Failed: " << filePath.c_str() << std::endl; return false; } E_TransferSyntax tfs = m_fileformat.getDataset()->getOriginalXfer(); DicomImage *pImage = new DicomImage(&m_fileformat, tfs); pImage->setWindow(m_image->WindowCenter, m_image->WindowWidth); PatternConversion(pImage, pattern, degree); Uint16 *pixelData = (Uint16*)(pImage->getOutputData(m_image->BitsAllocated)); if (pixelData == NULL) { std::cout << "Get Image Data Failed: " << filePath.c_str() << std::endl; return false; } cv::Mat dst(pImage->getWidth(), pImage->getHeight(), CV_16U, pixelData); cv::imshow(m_patient->PatientsName, dst); cv::waitKey(0); return true; } bool DicomProcessor::SavetoBMP(std::string filePath, Image_Pattern pattern, signed int degree) { if (!Read(filePath)) { std::cout << "Read Dicom File Failed: " << filePath.c_str() << std::endl; return false; } E_TransferSyntax tfs = m_fileformat.getDataset()->getOriginalXfer(); DicomImage *pImage = new DicomImage(&m_fileformat, tfs); pImage->setWindow(m_image->WindowCenter, m_image->WindowWidth); PatternConversion(pImage, pattern, degree); if (!pImage->writeBMP(GenerateImageName(filePath, pattern).c_str(), 8)) { std::cout << "Read Dicom File Failed: " << filePath.c_str() << std::endl; return false; } return true; } |
- 新增图像变换函数
1 | void PatternConversion(DicomImage* &image, Image_Pattern pattern, signed int degree = 0); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | void DicomProcessor::PatternConversion(DicomImage* &image, Image_Pattern pattern, signed int degree) { switch (pattern) { case ImagePattern_Normal: break; case ImagePattern_Flip: image->flipImage(); break; case ImagePattern_Rotate: image->rotateImage(degree); break; case ImagePattern_Polarity: image->setPolarity(EPP_Reverse); break; default: break; } } |
DicomInfo:加入图像变换类型定义
1 2 3 4 5 6 7 | enum Image_Pattern { ImagePattern_Normal = 1, ImagePattern_Flip, ImagePattern_Rotate, ImagePattern_Polarity }; |
DicomUtils:加入生成BMP文件名的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | __declspec(dllexport) std::string GenerateImageName(std::string name, Image_Pattern pattern); std::string GenerateImageName(std::string name, Image_Pattern pattern) { std::string prefix = ""; switch (pattern) { case ImagePattern_Normal: break; case ImagePattern_Flip: prefix = "_flip"; break; case ImagePattern_Rotate: prefix = "_rotate"; break; case ImagePattern_Polarity: prefix = "_polarity"; break; default: break; } auto last_pos = name.find_last_of("."); std::string srcName = name.substr(0, last_pos); std::cout << srcName << std::endl; std::string fileName = srcName + prefix + ".bmp"; return fileName; } |
Dicom_Sample加入调用代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | int main() { CreateDicomProcessor(); std::string readFile = "E:\\Learning\\DICOM\\Module_Sample\\MRBRAIN.dcm"; //if (!GetDicomProcessor()->ShowImage(readFile, ImagePattern_Flip)) //if (!GetDicomProcessor()->ShowImage(readFile, ImagePattern_Rotate, 90)); //if (!GetDicomProcessor()->ShowImage(readFile, ImagePattern_Polarity)) if (!GetDicomProcessor()->ShowImage(readFile)) { std::cout << "Read Dicom Image Failed: " << readFile.c_str() << std::endl; return -1; } if (!GetDicomProcessor()->SavetoBMP(readFile)) //if (!GetDicomProcessor()->SavetoBMP(readFile, ImagePattern_Flip)) //if (!GetDicomProcessor()->SavetoBMP(readFile, ImagePattern_Rotate, 90)) //if (!GetDicomProcessor()->SavetoBMP(readFile, ImagePattern_Polarity)) { std::cout << "Read Dicom Image Failed: " << readFile.c_str() << std::endl; return -1; } DeleteDicomProcessor(); return 0; } |