📄 lxdcmfilein.cpp.svn-base
字号:
#include "LXDicomDef.hpp"
#include "LXDcmFileIn.hpp"
#include <string.h>
CLXDcmFileIn::CLXDcmFileIn(const char *fileName )
{
this->m_bValid=false;
this->m_nWidth=0;
this->m_nHeigt=0;
this->m_nNumFrames=1;
this->m_nDepth=0;
this->m_nWindowLevel=0;
this->m_nWindowWidth=0;
this->m_nBitsAllocated=0;
short int nCols = 0, nRows = 0;
short int nBitsAllocatedTmp, nSamplesPerPixel = 1;
short int nHighBit = 0;
float fWindowWidth = 0, fWindowCenter = 0 , fRescaleSlope = 1, fRescaleIntercept = 0;
bool bIsSigned = false;
int nBytesP = 0;
this->m_nFrameSize = 0;
long int nLength;
char szTemp[32]="", szTransferSyntaxUID[65535]="";
bool bHaveSyntax=false;
bool bImplicitVR = true;
COMPRESSION_MODE nCompressionMode = COMPRESS_NONE;
DATA_ENDIAN nDataEndian = LITTLE_ENDIAN;
int nBytes;
FILE *fp;
this->m_pData = NULL;
short int gTag, eTag;
fp = fopen(fileName, "rb");
if (!fp)
{
printf("Failed to open file for read.\n");
return;
}
while(fread(&gTag, sizeof(short), 1, fp) == 1)
{
if (nDataEndian == BIG_ENDIAN)
SwapWord((char *) &gTag, 1);
switch(gTag)
{
case GTagMetaHeader: // Meta header.
if(bHaveSyntax)break;
{
fread(&eTag, sizeof(short), 1, fp);
// Meta header is always in Little Endian Explicit VR syntax.
switch(eTag)
{
case ETagTransferSyntaxUID: // Transfer syntax UID
readString(fp, szTransferSyntaxUID, false, LITTLE_ENDIAN);
bHaveSyntax=true;
// Check data endian.
if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.2")) // Explicit VR Big Endian
nDataEndian = BIG_ENDIAN; // Big Endian
else
nDataEndian = LITTLE_ENDIAN; // Little Endian
// Check if it is implicit VR or Explicit VR
if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2")) // Implicit VR Little Endian
bImplicitVR = true; // Implicit VR
else
bImplicitVR = false; // Explicit VR
// Parse the encapsulation/compression
if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.50")) // JPEG lossy
nCompressionMode = COMPRESS_JPEGLOSSY;
else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.51")) // JPEG lossy 12bit
nCompressionMode = COMPRESS_JPEGLOSSY12BIT;
else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.70")) // JPEG lossless first order prediction
nCompressionMode = COMPRESS_JPEGLOSSLESS;
else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.57")) // JPEG lossless process 14
nCompressionMode = COMPRESS_JPEGLOSSLESS2;
else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.5")) // RLE
nCompressionMode = COMPRESS_RLE;
break;
}
break;
}
case GTagImageInfo: // Image pixel data info group
{
fread(&eTag, sizeof(short), 1, fp);
if (nDataEndian == BIG_ENDIAN)
SwapWord((char *) &eTag, 1);
switch(eTag) //读取图象帧数,图象行数,图象列数,分配位数,存储位数,最高位数.
{
case ETagImageRows: // Rows
nRows = readUS(fp, nDataEndian);
this->m_nHeigt=nRows;
break;
case ETagImageColumns: // Columns
nCols = readUS(fp, nDataEndian);
this->m_nWidth=nCols;
break;
case ETagBitsAllocated: // Bits allocated --DICOM图象的象素数据一般为16 Bits或12 Bits两种。
//若数据为16Bits时,则每象素二字节;若数据为12 Bits时,则每象素字节分配情况就较为复杂,
//需要通过判别(0028,0100),(0028,0101),(0028,0102)的值来决定每像素分配位数,
//存储位数和像素的最高位情况。
nBitsAllocatedTmp = readUS(fp, nDataEndian);
this->m_nBitsAllocated=nBitsAllocatedTmp;
break;
case ETagBitsStored: //Bits Stored.
this->m_nDepth=readUS(fp,nDataEndian);
break;
case ETagImageHightBit: // High bit
nHighBit = readUS(fp, nDataEndian);
break;
case ETagImageIsSigned: // Is signed?
bIsSigned = readUS(fp, nDataEndian);
break;
case ETagSamplesPerPixel: // Samples per Pixel
nSamplesPerPixel = readUS(fp, nDataEndian);
this->m_bNumBytes=nSamplesPerPixel;
break;
case ETagImagePhotometric: // Photometric Interpolation
readString(fp, m_szPhotometric, bImplicitVR, nDataEndian);
break;
case ETagNumFrames: // Number of frames
m_nNumFrames = readIS(fp, bImplicitVR, nDataEndian);
break;
case ETagWindowCenter: // Window Center
//fWindowCenter = readDS(fp, bImplicitVR, nDataEndian);
//this->m_nWindowLevel=int(fWindowCenter);
this->m_nWindowLevel=readUS(fp,nDataEndian);
break;
case ETagWindowWidth: // Window Width
/*fWindowWidth = readDS(fp, bImplicitVR, nDataEndian);
this->m_nWindowWidth=int(fWindowWidth);*/
this->m_nWindowWidth=readUS(fp,nDataEndian);
break;
case ETagRescaleIntercept: // Rescale intercept
fRescaleIntercept = readDS(fp, bImplicitVR, nDataEndian);
break;
case ETagRescaleSlope: // Rescale slope
fRescaleSlope = readDS(fp, bImplicitVR, nDataEndian);
break;
default:
// do nothing
break;
}
break;
}
case GTagImagePixel: //图像数据区
{
fread(&eTag, sizeof(short), 1, fp);
if (nDataEndian == BIG_ENDIAN)
SwapWord((char *) &eTag, 1);
if (eTag == ETagImagePixelData)
{
nBytesP = nSamplesPerPixel*m_nBitsAllocated/8;
m_nFrameSize = nCols * nRows * nBytesP;//每帧图像大小
nLength = m_nNumFrames * m_nFrameSize;
if(nLength<=0)
{
return ;
}
switch(nCompressionMode)
{
case COMPRESS_NONE:
m_pData = new char[nLength + 16];
fseek(fp, 4, SEEK_CUR); // Skip 4 bytes (length bytes)
nBytes = fread(m_pData, 1, nLength, fp);
if (nBytes != nLength)
{
printf("Failed to read all pixel data.\n");
return;
}
break;
case COMPRESS_RLE:
printf("RLE compression not supported at this momen.t\n");
// To do:
// 1. Read the offset table.
// 2. Read and uncompress RLE image frames into either RGB or monochrome format.
// 3. Put frames in the pData buffer, one frame after another.
// Public domain RLE decompression source code is in Papyrus and dcmtk.
break;
case COMPRESS_JPEGLOSSY:
printf("JPEG lossy compression not supported at this moment");
// To do:
// 1. Read the offset table
// 2. Read and uncompress JPEG image frames into either RGB or monochrome format.
// 3. Put frames in the pData buffer, one frame after another.
// Public domain JPEG decompression source code is in Papyrus and dcmtk.
break;
case COMPRESS_JPEGLOSSY12BIT:
printf("JPEG lossy 12-bit compression not supported at this moment");
// To do:
// 1. Read the offset table
// 2. Read and uncompress JPEG image frames into either RGB or monochrome format.
// 3. Put frames in the pData buffer, one frame after another.
// Public domain JPEG decompression source code is in Papyrus and dcmtk.
break;
case COMPRESS_JPEGLOSSLESS:
case COMPRESS_JPEGLOSSLESS2:
printf("JPEG lossless compression not supported at this moment");
// To do:
// 1. Read the offset table
// 2. Read and uncompress JPEG image frames into either RGB or monochrome format.
// 3. Put frames in the pData buffer, one frame after another.
// Public domain JPEG decompression source code is in Papyrus and dcmtk.
break;
}
}
break;
}
if (m_pData)
break; // We are done.
}
}
fclose(fp);
if (m_pData) // Have we got the pixel data?
{
// Need to do byte swap?
if (nDataEndian == BIG_ENDIAN)
{
if (m_nBitsAllocated > 8)
SwapWord(m_pData, nLength/2);
}
/*
if (nBitsAllocated > 8)
{
// We need to convert it to 8-bit.
char *pNewData;
pNewData = convertTo8Bit(pData, nLength/2, bIsSigned, nHighBit,
fRescaleSlope, fRescaleIntercept, fWindowCenter, fWindowWidth);
// Use the new 8-bit data.
if (pNewData)
{
delete [] pData;
pData = pNewData;
nBytesP = 1;
nFrameSize /= 2;
nLength /= 2;
}
}
*/
}
this->m_bValid=true;
}
void CLXDcmFileIn::removeTailingSpace( char *pszStr )
{
char *cc = pszStr + strlen(pszStr) - 1;
while (((*cc == ' ') || (*cc == '\t')) && (cc != pszStr))
{
*cc -- = '\0';
}
}
void CLXDcmFileIn::SwapWord( char *pArray, int nWords )
{
char *cc = pArray, c0;
int i;
for (i = 0; i < nWords; i ++)
{
c0 = *cc;
*cc = *(cc + 1);
*(cc + 1) = c0;
cc += 2;
}
}
void CLXDcmFileIn::SwapDWord( char *pArray, int nDWords )
{
char *cc = pArray, c0;
int i;
// Rotate every four bytes
for (i = 0; i < nDWords; i ++)
{
// Swap first and last bytes
c0 = *cc;
*cc = *(cc + 3);
*(cc + 3) = c0;
// Swap middle two bytes
c0 = *(cc + 2);
*(cc + 2) = *(cc + 1);
*(cc + 1) = c0;
cc += 4;
}
}
int CLXDcmFileIn::readUS( FILE *fp, DATA_ENDIAN nDataEndian )
{
unsigned short nVal; //? Skip 128 bytes and "DICM" logo?
fseek(fp, 4, SEEK_CUR); // Skip VR and Length bytes (4)
fread(&nVal, 1, sizeof(short), fp); // read the unsigned short value
if (nDataEndian == BIG_ENDIAN)
{
SwapWord((char *) &nVal, 1);
}
return (int) nVal;
}
int CLXDcmFileIn::readIS( FILE *fp, bool bImplicitVR, DATA_ENDIAN nDataEndian )
{
char szTemp[64]="";
int nVal = 0;
readString(fp, szTemp, bImplicitVR, nDataEndian);
sscanf(szTemp, "%d", &nVal);
return nVal;
}
long int CLXDcmFileIn::readLength( FILE *fp, bool bImplicitVR, DATA_ENDIAN nDataEndian )
{
long int nValLength = 0;
short int nsLength;
if (bImplicitVR)
{
fread(&nValLength, sizeof(long), 1, fp);
if (nDataEndian == BIG_ENDIAN)
{
SwapDWord((char *) &nValLength, 1);
}
}
else
{
fseek(fp, 2, SEEK_CUR); // Skip 2 VR bytes
fread(&nsLength, sizeof(short), 1, fp);
if (nDataEndian == BIG_ENDIAN)
SwapWord((char *) &nsLength, 1);
nValLength = nsLength;
}
return nValLength;
}
int CLXDcmFileIn::readString( FILE *fp, char *pszStr, bool bImplicitVR, DATA_ENDIAN nDataEndian )
{
long int nValLength = 0;
int nVal = 0;
nValLength = readLength(fp, bImplicitVR, nDataEndian);
fread(pszStr, 1, nValLength, fp);
pszStr[nValLength] = '\0';
removeTailingSpace(pszStr);
return nVal;
}
float CLXDcmFileIn::readDS( FILE *fp, bool bImplicitVR, DATA_ENDIAN nDataEndian )
{
char szTemp[64]="";
float fVal = 0;
readString(fp, szTemp, bImplicitVR, nDataEndian);
sscanf(szTemp, "%f", &fVal);
return fVal;
}
char * CLXDcmFileIn::convertTo8Bit( char *pData, long int nNumPixels, bool bIsSigned, short nHighBit,
float fRescaleSlope, float fRescaleIntercept, float fWindowCenter,
float fWindowWidth )
{
unsigned char *pNewData = 0;
long int nCount;
short *pp;
// 1. Clip the high bits.
if (nHighBit < 15)
{
short nMask;
short nSignBit;
pp = (short *)pData;
nCount = nNumPixels;
if(bIsSigned == 0 ) // Unsigned integer
{
nMask = 0xffff << (nHighBit + 1);
while( nCount-- > 0 )
*(pp ++) &= ~nMask;
}
else
{
// 1's complement representation
nSignBit = 1 << nHighBit;
nMask = 0xffff << (nHighBit + 1);
while( nCount -- > 0 )
{
if ((*pp & nSignBit) != 0)
*(pp ++) |= nMask;
else
*(pp ++) &= ~nMask;
}
}
}
// 2. Rescale if needed (especially for CT)
if ((fRescaleSlope != 1.0f) || (fRescaleIntercept != 0.0f))
{
float fValue;
pp = (short *)pData;
nCount = nNumPixels;
while( nCount-- > 0 )
{
fValue = (*pp) * fRescaleSlope + fRescaleIntercept;
*pp ++ = (short)fValue;
}
}
// 3. Window-level or rescale to 8-bit
if ((fWindowCenter != 0) || (fWindowWidth != 0))
{
float fSlope;
float fShift;
float fValue;
unsigned char *np = new unsigned char[nNumPixels+4];
pNewData = np;
// Since we have window level info, we will only map what are
// within the Window.
fShift = fWindowCenter - fWindowWidth / 2.0f;
fSlope = 255.0f / fWindowWidth;
nCount = nNumPixels;
pp = (short *)pData;
while (nCount-- > 0)
{
fValue = ((*pp ++) - fShift) * fSlope;
if (fValue < 0)
fValue = 0;
else if (fValue > 255)
fValue = 255;
*np ++ = (unsigned char) fValue;
}
}
else
{
// We will map the whole dynamic range.
float fSlope;
float fValue;
int nMin, nMax;
unsigned char *np = new unsigned char[nNumPixels+4];
pNewData = np;
// First compute the min and max.
nCount = nNumPixels;
pp = (short *)pData;
nMin = nMax = *pp;
while (nCount-- > 0)
{
if (*pp < nMin)
nMin = *pp;
if (*pp > nMax)
nMax = *pp;
pp ++;
}
// Calculate the scaling factor.
if (nMax != nMin)
fSlope = 255.0f / (nMax - nMin);
else
fSlope = 1.0f;
nCount = nNumPixels;
pp = (short *)pData;
while (nCount-- > 0)
{
fValue = ((*pp ++) - nMin) * fSlope;
if (fValue < 0)
fValue = 0;
else if (fValue > 255)
fValue = 255;
*np ++ = (unsigned char) fValue;
}
}
return (char *)pNewData;
}
int CLXDcmFileIn::GetImageWidth()
{
return this->m_nWidth;
}
int CLXDcmFileIn::GetImageHeight()
{
return this->m_nHeigt;
}
char* CLXDcmFileIn::GetImageData()
{
return this->m_pData;
}
int CLXDcmFileIn::GetImageDepth()
{
return this->m_nDepth;
}
int CLXDcmFileIn::GetNumBytes()
{
return this->m_bNumBytes;
}
bool CLXDcmFileIn::IsValid()
{
return this->m_bValid;
}
int CLXDcmFileIn::GetWindowLevel()
{
return this->m_nWindowLevel;
}
int CLXDcmFileIn::GetWindowWidth()
{
return this->m_nWindowWidth;
}
int CLXDcmFileIn::GetChannel()
{
return this->m_bNumBytes;
}
int CLXDcmFileIn::GetBitsAllocated()
{
return this->m_nBitsAllocated;
}
CLXDcmFileIn::~CLXDcmFileIn()
{
if(m_pData)
{
delete [] m_pData;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -