醫療拍攝的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
}
}