前言:
转载请附上连接,本帖原创请勿照抄。
使用DCMTK库实现BMP转DCM的互相转换以及JPEG转DCM。使用DCMTK库其中在编译的时候错了好几次,在这有编译好的库给大家分享在此附上连接只需要1积分(https://download.csdn.net/download/qq_37529913/10793075)。直接使用DCMTK库实现的功能,期间本人也下载了好多但是大部分都没用复制粘贴出来的水贴有点多。其中借鉴了zssure大神的两篇文章(JPEGhttps://blog.csdn.net/zssureqh/article/details/42200303/)(BMPhttps://blog.csdn.net/zssureqh/article/details/42119303)zussre大神在贴中介绍了包括BMP、JPG结构和需要引入的一些文件,我在这再给大家介绍一些Dcm常用的Tag属性值(https://blog.csdn.net/wenzhi20102321/article/details/75127362)很感谢峥嵘life大佬,这里再给大家附上一个全的dcm的Tag(https://sno.phy.queensu.ca/~phil/exiftool/TagNames/DICOM.html)属于DICOM官方给出的标签很实用虽然没有详解。
使用VC++,MFC实现了Bmp和JPG的相互转换,JPEG转DCM图。包括dcm图Tag值的讲解以及实现。
DCMTK库的使用(使用VS大部分版本属性设置都是一样的)
VS2017项目->属性->
VC++目录->
包含目录填DCMTK库的include目录(X:\dcmtk库\include\)
库目录填DCMTK库的LIB目录(X:\dcmtk库\lib\)
C++常规->附加包含目录(X:\dcmtk库\include\)
预处理器添加(_CRT_SECURE_NO_WARNINGS)
链接器->输入->附加依赖项->
WS2_32.lib;NetAPI32.lib;WSock32.lib;charls.lib;dcmdata.lib;dcmdsig.lib;dcmimage.lib;dcmimgle.lib;dcmjpeg.lib;dcmjpls.lib;dcmnet.lib;dcmpstat.lib;dcmqrdb.lib;dcmsr.lib;dcmtls.lib;dcmwlm.lib;i2d.lib;ijg8.lib;ijg12.lib;ijg16.lib;oflog.lib;ofstd.lib;
引入头文件
#include "stdafx.h"
#include <stdio.h>
#include "afxdialogex.h"
#include "dcmtk/dcmimgle/dcmimage.h"
#include "dcmtk/dcmdata/dcistrmf.h"
#include "dcmtk/dcmdata/dctk.h"
#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmdata/libi2d/i2dbmps.h"
#include "dcmtk/dcmdata/dcpixel.h"
#include "dcmtk/dcmdata/dcpixseq.h"
#include "dcmtk/dcmdata/dcpxitem.h"
#include <direct.h>
/*----BMP图像解析----*/
#include "dcmtk/dcmdata/libi2d/i2dbmps.h"
/*----JPEG图像解析----*/
#include "dcmtk/dcmdata/libi2d/i2djpgs.h"
#include "dcmtk/dcmdata/libi2d/i2doutpl.h"
#include "dcmtk/dcmdata/dcerror.h"
BMP转DCM:
//CString BatchConversionFile bmp图片路径
OFCondition status;
DcmFileFormat fileformat;
DcmDataset* mydatasete = fileformat.getDataset();
AddDicomElements((DcmDataset*&)mydatasete);
Uint16 rows, cols, samplePerPixel, bitsAlloc, bitsStored, highBit, pixelRpr, planConf, pixAspectH, pixAspectV;
OFString photoMetrInt;
Uint32 length;
E_TransferSyntax ts;
//10
char* mydata = new char[1024 * 1024 * 110];
memset(mydata, 0, sizeof(char) * 1024 * 1024 * 110);
char* tmpData = mydata;
char curDir[100];
getcwd(curDir, 100);
//循环添加4张图片
for (int i = 0; i < 1; ++i)
{
OFString num;
char numtmp[100];
memset(numtmp, 0, sizeof(char) * 100);
sprintf(numtmp, "1.bmp", curDir, i + 1);
OFString filename = OFString(numtmp);
I2DBmpSource* bmpSource = new I2DBmpSource();
bmpSource->setImageFile(filename);
char* pixData = NULL;
bmpSource->readPixelData(rows, cols, samplePerPixel, photoMetrInt, bitsAlloc, bitsStored, highBit, pixelRpr, planConf, pixAspectH, pixAspectV, pixData, length, ts);
memcpy(tmpData, pixData, length);
tmpData += length;
delete bmpSource;
};
mydatasete->putAndInsertUint16(DCM_SamplesPerPixel, samplePerPixel);
mydatasete->putAndInsertString(DCM_NumberOfFrames, "1");
mydatasete->putAndInsertUint16(DCM_Rows, rows);
mydatasete->putAndInsertUint16(DCM_Columns, cols);
mydatasete->putAndInsertUint16(DCM_BitsAllocated, bitsAlloc);
mydatasete->putAndInsertUint16(DCM_BitsStored, bitsStored);
mydatasete->putAndInsertUint16(DCM_HighBit, highBit);
mydatasete->putAndInsertUint8Array(DCM_PixelData, (Uint8*)mydata, 1 * length);
mydatasete->putAndInsertOFStringArray(DCM_PhotometricInterpretation, photoMetrInt);
status = fileformat.saveFile("Multibmp2dcmtest.dcm", ts);
if (status.bad())
{
AfxMessageBox("BMP TO DCM Conversion Error");
}
return ;
Dcm转Bmp
//CString DcmFileTo图片的路径
// CString TheFileName输出的文件名
if (DcmFileTo.IsEmpty())
{
AfxMessageBox("DcmConversion_File NULL");
return;
}
if (TheFileName.IsEmpty())
{
AfxMessageBox("DcmConversion_Place NULL");
return;
}
DcmFileFormat *pDcmFile = new DcmFileFormat();
OFFilename filePath = DcmFileTo;
OFCondition pCondition = pDcmFile->loadFile(filePath);//filePath为DCM文件路径
if (pCondition.good())
{
E_TransferSyntax xfer = pDcmFile->getDataset()->getOriginalXfer();
DicomImage *pDicomImage = new DicomImage(pDcmFile, xfer);
pDicomImage->setWindow(100, 400);//调窗这里值设置不同出来的效果就会大不相同
char bmpto_file[100];
strncpy(bmpto_file, (LPCTSTR)TheFileName, sizeof(bmpto_file));
if (pDicomImage->writeBMP(bmpto_file)) {
}
else {
AfxMessageBox("非标准Dcm格式文件转换失败");
return;
}
}
JPEG转DCM:
/*CString TheJPGFile图片路径
*/
if (TheJPGFile.IsEmpty())
{
AfxMessageBox(" JPG File Error");
return;
}
//TheName 输出的后缀 TheFile 获取到的第一张BMP图的文件名 TheFileName 输出的文件名
CString TheName = ".dcm", TheFileName, The_Name = "_T.dcm", The_FileName;
//删除路径多余符号
int nPos = TheJPGFile.Find('\\');
CString sSubStr = TheJPGFile;
while (nPos)
{
sSubStr = sSubStr.Mid(nPos + 1, sSubStr.GetLength() - nPos); //取'\'右边字符串
nPos = sSubStr.Find('\\'); //不包含'\',函数值返回-1
if (nPos == -1)
{
nPos = 0;
}
}
//删除后缀
int pos = sSubStr.ReverseFind('.');
if (pos > 0) {}
CString strRet = sSubStr.Left(pos);
//输出的文件名
TheFileName = strRet + TheName;
The_FileName = strRet + The_Name;
OFCondition status;
DcmPixelSequence *seq = new DcmPixelSequence(DcmTag(DCM_PixelData, EVR_OB));
DcmFileFormat fileformat;
DcmDataset* mydatasete = fileformat.getDataset();
AddDicomElements((DcmDataset*&)mydatasete);
Uint16 rows, cols, samplePerPixel, bitsAlloc, bitsStored, highBit, pixelRpr, planConf, pixAspectH, pixAspectV;
OFString photoMetrInt;
Uint32 length;
E_TransferSyntax ts;
char curDir[255];
getcwd(curDir, 255);
seq->insert(new DcmPixelItem(DcmTag(DCM_Item, EVR_OB)));
for (int i = 0; i < 1; ++i)
{
OFString num;
char numtmp[255];
memset(numtmp, 0, sizeof(char) * 255);
sprintf(numtmp, TheJPGFile, curDir, i + 1);
OFString filename = OFString(numtmp);
I2DJpegSource* bmpSource = new I2DJpegSource();
bmpSource->setImageFile(filename);
char* pixData = NULL; //photoMetrInt
bmpSource->readPixelData(rows, cols, samplePerPixel, photoMetrInt, bitsAlloc, bitsStored, highBit, pixelRpr, planConf, pixAspectH, pixAspectV, pixData, length, ts);
DicomImage *pDicomImage = new DicomImage(TheJPGFile);
pDicomImage->setWindow(3570, 5020);//调窗这里值设置不同出来的效果就会大不相同
DcmPixelItem *newItem = new DcmPixelItem(DcmTag(DCM_Item, EVR_OB));
if (newItem != NULL)
{
seq->insert(newItem);
OFCondition result = newItem->putUint8Array((Uint8*)pixData, length);
//OFCondition result = newItem->putUint16Array((Uint16*)pixData, length);
}
delete bmpSource;
};
OFFilename str_FileName = TheFileName;
//pDicomImage->setWindow(100, 400);
mydatasete->putAndInsertUint16(DCM_SamplesPerPixel, samplePerPixel);
mydatasete->putAndInsertString(DCM_NumberOfFrames, "1");
mydatasete->putAndInsertUint16(DCM_Rows, rows);
mydatasete->putAndInsertUint16(DCM_Columns, cols);
mydatasete->putAndInsertUint16(DCM_BitsAllocated, bitsAlloc);
mydatasete->putAndInsertUint16(DCM_BitsStored, bitsStored);
mydatasete->putAndInsertUint16(DCM_HighBit, highBit);
mydatasete->putAndInsertOFStringArray(DCM_PhotometricInterpretation, photoMetrInt);//"MONOCHROME2"
mydatasete->putAndInsertString(DCM_UltrasoundColorDataPresent, "0");
mydatasete->putAndInsertUint16(DCM_SamplesPerPixel, 1);
mydatasete->insert(seq, OFFalse, OFFalse);
//????
mydatasete->putAndInsertString(DCM_SourceApplicationEntityTitle, "Holter");
mydatasete->putAndInsertString(DCM_SOPClassUID, "1.2.840.10008.5.1.4.1.17");
mydatasete->putAndInsertString(DCM_SOPInstanceUID, "1.2.7.3.8.2019.02.08.00.16.28.1.1");
status = fileformat.saveFile(str_FileName, ts);
if (status.bad())
{
AfxMessageBox("Error");
}
return;
PS:以上是三种转换方式楼主亲测,虽然补了很多漏洞,毕竟努力了好久了完整版的就不发出来了,把大概的实现发出来了。AddDicomElements((DcmDataset*&)mydatasete);这个删掉就好缺什么字段在后面使用mydatasete->这个添加就好,有三四处内存泄漏需要各位小伙伴自己找一下,dcmtk的标准还有一些字段的意思还得大家自己去研究,按照这个改一改完整版的完全可以做出来,有什么问题可以留言,看到会及时回复的。(如果对你有帮助记得点赞关注在走哦)
附加的完整Lib包下载链接(https://download.csdn.net/download/qq_37529913/11013779);