转自 http://bbs.csdn.net/topics/390146622
医学影像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('\0')<<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] = '\0';
- 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;
- }