DICOM医学图像处理:BMP转DCM、DCM转BMP、多张BMP转DCM、JPG转DCM,,多张JPG转DCM。

本文介绍如何使用DCMTK库实现BMP、JPEG与DCM格式图像之间的转换,包括代码实例与常见问题解决方法。

      使用DCMTK库实现BMP转DCM的互相转换以及JPEG转DCM。使用DCMTK库其中在编译的时候错了好几次,在这有编译好的库给大家分享在此附上连接只需要1积分(DCMTK编译好的库-C/C++其他资源-CSDN下载)。直接使用DCMTK库实现的功能,期间本人也下载了好多但是大部分都没用复制粘贴出来的水贴有点多。其中借鉴了zssure大神的两篇文章(JPEGDICOM医学图像处理:DICOM存储操作之 “多幅JPG图像数据存入DCM文件”_zssure的博客-CSDN博客)(BMPDICOM医学图像处理:DICOM存储操作之“多幅BMP图像数据存入DCM文件”_zssure的博客-CSDN博客_dicom存储)zussre大神在贴中介绍了包括BMP、JPG结构和需要引入的一些文件,我在这再给大家介绍一些Dcm常用的Tag属性值(dicom文件详细解析_峥嵘life的博客-CSDN博客_dicom解析)很感谢峥嵘life大佬,这里再给大家附上一个全的dcm的Tag(DICOM Tags)属于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包下载链接(dcmtk图片转换附加库-C++其他资源-CSDN下载);

软件介绍: DcmTransform是一款专用的医学格式转换器,于对符合DICOM 3.0标准的医学图像文件。软件首先对DICOM文件中的数据进行解析,并将其以图像的样式显示。图像显示后,用户可以自定义地调节医学图像的窗位窗宽。由于医学图像数据的像素变化范围通常为0-4095或0-1023,不同于传统图像文件的0-255。而计算机所能显示的黑白像素范围是0-255,所以需要对医学图像进行像素值的映射处理,即调节医学图像的窗位窗宽。调节操作的作用在于改变显示图像的明暗度对比度。当用户调节好医学图像的窗位窗宽后,即可以对医学图像文件进行格式化。化的文件格式可设为BMP格式JPG格式。用户亦可以根据自己的需要设置化图像的属性信息,如图像的质量,大小。对于CT,MRI断层图像来说,通常拍摄得到的是一系列DICOM文件,该系列文件通常在同一个文件夹目录下。对于某一系列文件,由于拍摄中设备参数设置不变,其像素的变化范围,图像的明暗度饱度基本相同,所以在图像化操作中,用户可以调节好窗位窗宽后,一次性的将系列文件全部化。对于DSA血管减影造影图像,也是需要拍摄一系列的图像,该系列图像通常保存在同一DICOM文件中。它借助计算机对血管造影图像进行数字图像处理,以消除背景的干扰,突出医生感兴趣的血管部分的信息。医学关心的并不是原始拍摄的图像信息,而是减影成像后的图像。所以本软件即可以将原始图像数据化成普通图像文件,也可以化减影成像后的图像。DICOM文件是按照DICOM标准存储的医学文件,它不仅可以用来封装各种医学图像,也可以封装其它医学信息,如病人姓名,性别,拍摄单位、设备参数等。这类资料保存在DICOM文件的文件头中,DICOM文件头包含了标识数据集合的相关信息。DICOM文件一般由1个DICOM文件头1个DICOM数据集合组成。在对DICOM文件处理过程序中,亦需要对其文件头进行解析,得到图像的相关信息。本软件可以将解析后的文件头保存为TXT文本文件,以便于查看。本软件还为用户提供了普通图像文件浏览的功能,以便于用户化完DICOM文件后,查看化效果。图像浏览时,先列出所有化后图像的缩略图,用户点击任意一幅缩略图即可打开该图像。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

双子座断点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值