醫學影像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
{
short group = *(short*)(dcm+p);
p+=2;
short element = *(short*)(dcm+p);
p+=2;
//cout<
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
dib[i] ^= 0xFFFF;
windowLevel = 65535-windowLevel;
}
delete[] dcm;
return dib;
}
void dcmReleaseImage(unsigned short* dib)
{
delete[] dib;
}