解压缩读取Dicom图片(彩色)及显示

1. 前言

在开发新课题的时候需要使用到Dicom的彩色图像,由于之前一直读取的是Dicom的灰度图像,然后也就惯性思维的使用读取灰度图像的方式去读取压缩过后的彩色图像,结果可想而知图片数据根本无法读取出来。然后经过痛苦的寻找,终于找到解压Dicom图像数据和读取显示的方法,本文将分享这个方法。测试图片

2. 读取

这里给出的方法是在之前的基础上进行修改的,这里就直接贴出代码,写得也比较明了

头文件:

//包含DCMTK 头文件和lib  
#include "dcmtk/config/osconfig.h"  
#include "dcmtk/dcmdata/dctk.h"  
#include "dcmtk/dcmdata/dcrledrg.h"
#include "dcmtk/dcmimgle/dcmimage.h"  
#include "dcmtk/dcmimage/diregist.h"
#include "dcmtk/dcmjpeg/djdecode.h"

#pragma comment(lib, "Netapi32.lib")  
#pragma comment(lib, "ws2_32.lib") 

实现代码:

void LoadDcmFile(std::string filepath)
{
	std::string file_path = "201608171023044706.dcm";										//dcm文件

	DcmFileFormat fileformat;
	OFCondition oc = fileformat.loadFile(file_path.c_str());					//读取Dicom图像
	if (!oc.good())		//判断Dicom文件是否读取成功
	{
		std::cout << "file Load error" << std::endl;
		return;
	}
	DcmDataset *dataset = fileformat.getDataset();								//得到Dicom的数据集
	E_TransferSyntax xfer = dataset->getOriginalXfer();							//得到传输语法

	OFString patientname;
	dataset->findAndGetOFString(DCM_PatientName, patientname);					//获取病人姓名

	unsigned short bit_count(0);
	dataset->findAndGetUint16(DCM_BitsStored, bit_count);						//获取像素的位数 bit

	OFString isRGB;
	dataset->findAndGetOFString(DCM_PhotometricInterpretation, isRGB);			//DCM图片的图像模式

	unsigned short img_bits(0);
	dataset->findAndGetUint16(DCM_SamplesPerPixel, img_bits);					//单个像素占用多少byte

	//DicomImage* img_xfer = new DicomImage(xfer, 0, 0, 1);						//由传输语法得到图像的帧

	unsigned short m_width;														//获取图像的窗宽高
	unsigned short m_height;
	dataset->findAndGetUint16(DCM_Rows, m_height);
	dataset->findAndGetUint16(DCM_Columns, m_width);


	/////////////////////////////////////////////////////////////////////////
	const char*	transferSyntax = NULL;
	fileformat.getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, transferSyntax);		//获得传输语法字符串
	string losslessTransUID = "1.2.840.10008.1.2.4.70";
	string lossTransUID = "1.2.840.10008.1.2.4.51";
	string losslessP14 = "1.2.840.10008.1.2.4.57";
	string lossyP1 = "1.2.840.10008.1.2.4.50";
	string lossyRLE = "1.2.840.10008.1.2.5";
	if (transferSyntax == losslessTransUID || transferSyntax == lossTransUID ||
		transferSyntax == losslessP14 || transferSyntax == lossyP1)
	{
		DJDecoderRegistration::registerCodecs();
		dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL);						//对压缩的图像像素进行解压
		DJDecoderRegistration::cleanup();
	}
	else if (transferSyntax == lossyRLE)
	{
		DcmRLEDecoderRegistration::registerCodecs();
		dataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL);
		DcmRLEDecoderRegistration::cleanup();
	}
	else
	{
		dataset->chooseRepresentation(xfer, NULL);
	}

	DcmElement* element = NULL;
	OFCondition result = dataset->findAndGetElement(DCM_PixelData, element);	//获取图像数据
	if (result.bad() || element == NULL)
		return;
	Uint8* image_data = nullptr;
	Uint16* image16_data = nullptr;
	if (8 == bit_count)
	{
		result = element->getUint8Array(image_data);		//获取8位的图像数据
	}
	else if (8 < bit_count)
	{
		result = element->getUint16Array(image16_data);		//获取>8位的图像数据
	}
	
	if (image_data != NULL || image16_data!=NULL)
	{
		if (1 == img_bits)		//1 byte per pixel
		{
			cv::Mat dst(m_height, m_width, CV_8UC1, cv::Scalar::all(0));
			unsigned char* data = nullptr;
			for (int i = 0; i < m_height; i++)
			{
				data = dst.ptr(i);	//取得每一行的头指针 也可使用dst2.at(i, j) = ?
				for (int j = 0; j < m_width; j++)
				{
					*data++ = (unsigned char)((float)image16_data[i*m_width + j] * 255.0 / std::pow(2.0, bit_count) + 0.5);
				}
			}
			cv::imshow("gray", dst);
			cv::waitKey(0);
		}
		else if (3 == img_bits)		//3 bytes per pixel
		{
			cv::Mat dst(m_height, m_width, CV_8UC3, cv::Scalar::all(0));
			unsigned short* data = nullptr;
			for (int i = 0; i < m_height; i++)
			{
				for (int j = 0; j < m_width; j++)
				{
					dst.at(i, j)[0] = *(image_data + i*m_width * 3 + j * 3 + 2);	//B	channel
					dst.at(i, j)[1] = *(image_data + i*m_width * 3 + j * 3 + 1);	//G channel
					dst.at(i, j)[2] = *(image_data + i*m_width * 3 + j * 3);		//R channel
				}
			}
			cv::imshow("colored", dst);
			cv::waitKey(0);
		}
	}
}

读取方法2:

        DicomImage* m_dcmImage = new DicomImage((DcmObject*)dataset, xfer); //利用dataset生成DicomImage,需要上面的解压方法;
	unsigned char *pixelData = (unsigned char*)(m_dcmImage->getOutputData(8, 0, 0));	//获得16位的图像数据指针
	if (pixelData != NULL)
	{
		cv::Mat dst2(m_height, m_width, CV_8UC3, cv::Scalar::all(0));
		unsigned short* data = nullptr;
		for (int i = 0; i < m_height; i++)
		{
			//data = dst2.ptr(i);	//取得每一行的头指针 也可使用dst2.at(i, j) = ?
			for (int j = 0; j < m_width; j++)
			{
				dst2.at(i, j)[0] = *(pixelData + i*m_width * 3 + j * 3 + 2);	//B	channel
				dst2.at(i, j)[1] = *(pixelData + i*m_width * 3 + j * 3 + 1);	//G channel
				dst2.at(i, j)[2] = *(pixelData + i*m_width * 3 + j * 3);		//R channel
			}
		}
		cv::imshow("image", dst2);
		cv::waitKey(0);
	}

3. 显示结果

灰度:

解压缩读取Dicom图片(彩色)及显示_第1张图片

彩色:左边为测试的显示图片,右边为测试的比对图片

解压缩读取Dicom图片(彩色)及显示_第2张图片

你可能感兴趣的:([8]图像处理相关)