医疗拍摄的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
}
}