DCM医学影像文件的格式与读取方法分享

医学影像DCM是个类似PNG的分块格式,内涵丰富医疗信息,由于应用领域较窄,OpenCV没有提供对其加载支持,一般采用dcmtk库进行加载。

博主本着研究探索的精神写了这段代码,并分享出来,提供了解析DCM的DIB数据、宽高、窗宽窗位、像素间距的功能,支持反色DCM。

将来可以参考spec文档进行扩充,可以在大框架中加入块的处理,从而抽取更多感兴趣的信息,也可以加入压缩DCM的支持。

// 输入:文件名
// 输出:宽高 窗宽窗位 像素间距 dib
unsigned short* dcmLoadImage(char* fn, int& width, int& height, int& windowWidth, int& windowLevel, double& pixelSpacing)
{
	// 读取整个文件到内存
	FILE* f = fopen(fn, "rb");
	fseek(f, 0, SEEK_END);
	int dcmSize = ftell(f);
	fseek(f, 0, SEEK_SET);
	unsigned char* dcm = new unsigned char[dcmSize];
	fread(dcm, dcmSize, 1, f);
	fclose(f);
	
	// 解析
	width = -1;
	height = -1;
	windowWidth = -1;
	windowLevel = -1;
	pixelSpacing = 0.0;
	bool invert = false;
	unsigned short* dib = NULL;
	int dibSize = -1;
	int p = 132;
	while( p<dcmSize )
	{
		short group = *(short*)(dcm+p);
		p+=2;
		short element = *(short*)(dcm+p);
		p+=2;
		//cout<<setfill(0)<<hex<<setw(4)<<group<<","<<setw(4)<<element<<setfill()<<dec<<endl;


		if(group==0x0002)
		{
			if(element==0x0001)// 2,1
			{
				p+=10;
			}
			else// 2,*
			{
				char vr[3];
				vr[0] = dcm[p++];
				vr[1] = dcm[p++];
				vr[2] = ;
				short size = *(short*)(dcm+p);
				p+=2;
				p+=size;
			}
		}
		else// *
		{
			int size = *(int*)(dcm+p);
			p+=4;
			if(size==-1)
				size=0;
			if(group==0x0028&&element==0x0010)
				height = *(short*)(dcm+p);
			if(group==0x0028&&element==0x0030)
				pixelSpacing = atof((char*)dcm+p);
			if(group==0x0028&&element==0x0004)
				invert = !strncmp((char*)dcm+p, "MONOCHROME1", 11);
			else if(group==0x0028&&element==0x0011)
				width = *(short*)(dcm+p);
			else if(group==0x0028&&element==0x1050)
				windowLevel = atoi((char*)dcm+p);
			else if(group==0x0028&&element==0x1051)
				windowWidth = atoi((char*)dcm+p);
			else if(group==0x7FE0&&element==0x0010)
			{
				dibSize = size;
				dib = new unsigned short[dibSize];
				memcpy(dib, dcm+p, dibSize);
			}
			p+=size;
		}
	}
	assert(p==dcmSize);
	assert(width!=-1);
	assert(height!=-1);
	assert(windowLevel!=-1);
	assert(windowWidth!=-1);
	assert(dib!=NULL);
	assert(dibSize==width*height*2);
	
	// 反图做修正
	if(invert)
	{
		for(int i=0; i<width*height; i++)
			dib[i] ^= 0xFFFF;
		windowLevel = 65535-windowLevel;
	}
	
	delete[] dcm;
	return dib;
}


void dcmReleaseImage(unsigned short* dib)
{
	delete[] dib;
}


经验分享 程序员 微信小程序 职场和发展