医疗dcm格式图像解析成bmp格式图片

         医疗拍摄的dcm格式图像一般不能直观的给我们展示出来,需要使用程序对里面的元素进行解析。一般我们用ViewPersonal软件来查看dcm格式的图像。


        dcm格式图像解析过程一般如有图所示:

       其中dcm图像中需要解析的元素键值如下表

SamplesPerPixel 1表示灰度图像3表示彩色图像
BitsAllocated 每一种颜色值所分配的存储位数
RescaleSlope 像素值的比例系数
RescaleIntercept 像素值的比例参数
BitsStored 像素值的实际存储位数
HighBit 像素值存储的最高位
WindowCenter 窗位
WindowWidth 窗宽

注意点:获取的像素值需要进行转化    实际像素值 = RescaleSlope * 获取像素值 + RescaleIntercept,若BitsAllocated超过8会超出颜色值的表示范围0~255需要对其进行转化.

图像格式存储参考文章:DICOM医学技术及DIB显示

  若存储的是灰度图像则RGB三种色值的大小一样,值存储一种颜色值,当转化为其它图像格式时需要对其进行扩充。

void TestSaveBmp(const string& strSrcFile)
{
	DcmFileFormat dcmFileFormat;//将dcm格式文件读取出来解析相关类
	OFCondition oc = dcmFileFormat.loadFile(strSrcFile.c_str());
	if(oc.bad())
		return;
	DcmDataset* pDataset = dcmFileFormat.getDataset();//得到dcm文件的数据

	int nWidth, nHeight, nBandCount, nWindowWidth, nWindowCenter,nRescaleSlope,nRescaleIntercept,nBitsAllocated,nHighBit,
		nNumberOfFrames;
	OFString strInstanceNumber, strWidth, strHeight, 
		strWindowWidth, strWindowCenter, strSamplesPerPixel,
		strRescaleSlope,strRescaleIntercept,strBitsAllocated,strHighBit,strNumberOfFrames;

	//读取dcm格式文件里相关元素值
	pDataset->findAndGetOFString(DCM_InstanceNumber, strInstanceNumber);
	pDataset->findAndGetOFString(DCM_Columns ,strWidth);
	pDataset->findAndGetOFString(DCM_Rows ,strHeight);
	pDataset->findAndGetOFString(DCM_WindowWidth ,strWindowWidth);
	pDataset->findAndGetOFString(DCM_WindowCenter ,strWindowCenter);
	pDataset->findAndGetOFString(DCM_SamplesPerPixel ,strSamplesPerPixel);
	pDataset->findAndGetOFString(DCM_RescaleSlope ,strRescaleSlope);
	pDataset->findAndGetOFString(DCM_RescaleIntercept,strRescaleIntercept);
	pDataset->findAndGetOFString(DCM_BitsAllocated,strBitsAllocated);
	pDataset->findAndGetOFString(DCM_HighBit,strHighBit);
	pDataset->findAndGetOFString(DCM_NumberOfFrames,strNumberOfFrames);

	nWidth = atoi(strWidth.c_str());
	nHeight = atoi(strHeight.c_str());
	if(strSamplesPerPixel.empty())
	{
		strSamplesPerPixel = "1";//若没有说明哪种类型图像,默认为灰度图像
	}
	if(strRescaleSlope.empty())
	{
		strRescaleSlope = "1";//像素转换的比例系数,没有则默认存储为1
	}
	if(strRescaleIntercept.empty())
	{
		strRescaleIntercept = "0";//像素转换的比例参数,没有则默认存储为0
	}
	nBandCount = atoi(strSamplesPerPixel.c_str());
	nWindowWidth = atoi(strWindowWidth.c_str());
	nWindowCenter = atoi(strWindowCenter.c_str());
	nRescaleSlope = atoi(strRescaleSlope.c_str());
	nRescaleIntercept = atoi(strRescaleIntercept.c_str());
	nBitsAllocated = atoi(strBitsAllocated.c_str());
	nHighBit = atoi(strHighBit.c_str());
	nNumberOfFrames = atoi(strNumberOfFrames.c_str());

	E_TransferSyntax opt_oxfer = pDataset->getOriginalXfer();
    //图像存储的压缩格式
	if(EXS_RLELossless == opt_oxfer)
	{
		E_TransferSyntax opt_oxfer = EXS_RLELossless;
		OFBool opt_uidcreation = OFFalse;
		OFBool opt_reversebyteorder = OFFalse;
		DcmRLEDecoderRegistration::registerCodecs(opt_uidcreation, opt_reversebyteorder);
		DcmXfer original_xfer(opt_oxfer);
		if (!original_xfer.isEncapsulated())
			return;
		oc = pDataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL);
		if (oc != EC_Normal)
			return;
	}
	else if(opt_oxfer >= EXS_JPEGProcess1TransferSyntax && opt_oxfer <= EXS_JPEGLSLossy)
	{
		E_DecompressionColorSpaceConversion opt_decompCSconversion = EDC_guessLossyOnly;
		E_UIDCreation    opt_uidcreation = EUC_default;
		DJDecoderRegistration::registerCodecs(opt_decompCSconversion, opt_uidcreation);
		DcmXfer original_xfer(opt_oxfer);
		if (!original_xfer.isEncapsulated())
			return;
		oc = pDataset->chooseRepresentation(EXS_LittleEndianExplicit, NULL);
		if(oc != EC_Normal)
			return;
	}
	DcmElement* element = NULL;
	OFCondition result = pDataset->findAndGetElement(DCM_PixelData, element);//获取文件中存储的像素元素
	long nCount = nWidth * nHeight;//unsigned char
	if(nBandCount == 3)
		nCount *= 3;//若是RGB彩色图像则有R,G,B三种色彩值进行存储
	unsigned char *pRgbData = new unsigned char[nCount];
	if(8 == nBitsAllocated)
	{
		Uint8* pixData = NULL;
		result = element->getUint8Array(pixData);
		if(result.good() && pixData != NULL)
		{
			if(pRgbData != NULL)
			{
				for(long i = 0; i < nCount; i++)
				{
					while(nBitsAllocated - nHighBit > 0)
					{
						pixData[i] &= ~(1 << nHighBit);
						nHighBit++;
					}
					pRgbData[i] = nRescaleSlope*pixData[i] + nRescaleIntercept;
				}
			}
				Save2Bmp(pRgbData,nWidth,nHeight,nBandCount);
			}
	}
	else if(16 == nBitsAllocated)//若颜色值存储为16位,则有可能超出颜色的表示范围(0~255)此时需要对其进行转化
	{
		Uint16* pixData = NULL;
		result = element->getUint16Array(pixData);
		if(result.good() && pixData != NULL)
		{
			if(pRgbData != NULL)
			{
				//short *pshort = (short *)pixData;
				for(long i = 0; i < nCount; i++)
				{
					while(nBitsAllocated - nHighBit > 0)
					{
						pixData[i] &= ~(1 << nHighBit);
						nHighBit++;
					}
					int data= nRescaleSlope*pixData[i] + nRescaleIntercept;
					//float fdata = float (nRescaleSlope*pixData[i] + nRescaleIntercept);
					if(data < nWindowCenter - nWindowWidth/2)
					{
						pRgbData[i] = 0;
					}
					else if(data > nWindowCenter + nWindowWidth/2)
					{
						pRgbData[i] = 0xFF;
					}
					else
					{
						double dValue = (data + nWindowWidth/2.0f - nWindowCenter)*255.0f/nWindowWidth;

						int nGray = 0;
						if(dValue < 0)
						{
							nGray = 0;
						}
						else if(dValue > 255)
						{
							nGray = 255;
						}
						else
						{
							nGray = (int)dValue;
						}

						pRgbData[i] = nGray;
					}
				}
				Save2Bmp(pRgbData,nWidth,nHeight,nBandCount);
			}
		}
	}
	if(NULL != pRgbData)
	{
		delete []pRgbData;
		pRgbData = NULL;
	}
	if(EXS_RLELossless == opt_oxfer)
	{
		DcmRLEDecoderRegistration::cleanup();
	}
	else if(opt_oxfer >= EXS_JPEGProcess1TransferSyntax && opt_oxfer <= EXS_JPEGLSLossy)
	{
		DJDecoderRegistration::cleanup(); // deregister JPEG codecs
	}
	}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章