⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lxdcmfilein.cpp.svn-base

📁 dicom 文件读写
💻 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 + -