醫療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
	}
	}

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