/* Example: dcm d; d.Load(filename.c_str()); WORD *pImg = (WORD*)(d.ppData[i]); memcpy(pInArray[ 1 ], (WORD*)(d.ppData[i]), d.nHeight * d.nWidth * sizeof(WORD)); */ #pragma once #include #include #include #include //使用stringstream需要引入这个头文件 #include "LogLocalHelper.h" #include "Log4CPP.h" using namespace std; //extern Log4CPP::Logger* mLog::gLogger; class dcm { public: int nWidth, nHeight, nBits, nFrames, nWindowCenter, nWindowWidth; void ** ppData; string PatientName, SOPInstanceUID; int filesize; bool bLoaded; dcm() : nWidth(0), nHeight(0), nBits(0), ppData(0), bLoaded(false) { }; ~dcm() { Destroy(); } void Destroy() { if (ppData != NULL) { for (int i = 0; i < nFrames; i++) { if (ppData[i] != NULL) { free(ppData[i]); ppData[i] = NULL; } } free(ppData); ppData = NULL; } nWidth = nHeight = nBits = 0; bLoaded = false; }; unsigned short & operator()(int h, int w, int f = 0) { return ((unsigned short*)(ppData[f]))[h * nWidth + w]; } //unsigned short & operator()(int index, int f = 0) { return ((unsigned short*)(ppData[f]))[index]; } void Load_raw_file(const char* filename) { char tmp[64] = { 0 }, str[32] = { 0 }; char *p1, *p2; strncpy(tmp, filename, sizeof(tmp) - 1); tmp[strlen(filename) - 4] = '\0'; p2 = strrchr(tmp, '_'); int loc2 = p2 - tmp; strncpy(str, p2 + 1, sizeof(str) - 1); nHeight = atoi(str); tmp[loc2] = '\0'; p1 = strrchr(tmp, '_'); int loc1 = p1 - tmp; strncpy(str, p1 + 1, sizeof(str) - 1); nWidth = atoi(str); nBits = 16; nFrames = 1; ppData = (void**)malloc(sizeof(void*) * nFrames); ppData[0] = (unsigned short*)malloc(sizeof(unsigned short) * nHeight * nWidth); FILE* fid = fopen(filename, "rb"); if (fid != NULL) { size_t nBytes = fread(ppData[0], sizeof(unsigned short), nHeight * nWidth, fid); fclose(fid); bLoaded = true; } else { // 处理文件打开失败的情况 bLoaded = false; // 可以在这里添加错误处理代码,如释放已分配的内存 if (ppData != NULL) { free(ppData[0]); free(ppData); ppData = NULL; } } bLoaded = true; } bool Load(const char* filename) { bool isLitteEndian = false;//是否小字节序(小端在前 、大端在前) bool isExplicitVR = false;//有无VR // key info for image data int height = 0, width = 0, nHighBit = 0, nBitsAllocated = 0; bool bSigned = false; int windowCenter = 0, windowWidth = 0; double rescaleIntercept, rescaleSlope; bool bInverse = false; nFrames = 1; int nRet = 0; isLitteEndian = true;//是否小字节序(小端在前 、大端在前) isExplicitVR = true;//有无VR // read tag,VR,VF... int tag = 0; std::string VR, VF; int VFlen = 0; // info folder bool endDir = false; int level = 0; FILE *f = 0; f = fopen(filename, "rb"); if (f == NULL) { FERROR("open %s fail!", filename); return false; } fseek(f, 0L, SEEK_END); /* 定位到文件末尾 */ filesize = ftell(f); /* 得到文件大小 */ FINFO("file size:{$}", filesize); fseek(f, 0L, SEEK_SET); /* 定位到文件开头 */ fseek(f, 128, SEEK_SET); if (!(getString(f, 4) == "DICM")) { fclose(f); FERROR("getString fail!"); return false; } while (true) { tag = getTag(f, isLitteEndian); if (tag == 0) { int len = ftell(f); FINFO("offset length:{$}",len); fclose(f); FERROR("getTag fail!"); return false; } // getVR if (isExplicitVR == false) { VR = getInExplicitVR(tag); VFlen = getInt32(f, isLitteEndian); } else { if ((tag & 0x000f0000) == 0x00020000)//文件头 特殊情况 { VR = getVR(f); if (VR == "OB" || VR == "OW" || VR == "SQ" || VR == "OF" || VR == "UT" || VR == "UN") { nRet = fseek(f, 2, SEEK_CUR); if (nRet) { FERROR("fseek error! offset:{$}", ftell(f)); } VFlen = getInt32(f, isLitteEndian); } else { VFlen = getShort16(f, isLitteEndian); } //FINFO("111 VR:{$},VFlen:{$}", VR, VFlen); } else if (tag == 0xffffe000 || tag == 0xffffe00d || tag == 0xffffe0dd)//文件夹标签 { VR = "**"; VFlen = getInt32(f, isLitteEndian); //FINFO("222 VR:{$},VFlen:{$}", VR, VFlen); } else { VR = getVR(f); if (VR == "OB" || VR == "OW" || VR == "SQ" || VR == "OF" || VR == "UT" || VR == "UN") { nRet = fseek(f, 2, SEEK_CUR); if (nRet) { FERROR("fseek error! offset:{$}", ftell(f)); } VFlen = getInt32(f, isLitteEndian); } else { VFlen = getShort16(f, isLitteEndian); } //FINFO("333 VR:{$},VFlen:{$}", VR, VFlen); } } // getVF //判断是否应该读取VF 以何种方式读取VF //--------------这些都是在读取VF一步被阻断的情况 if ((tag == 0xffffe000))//遇到文件夹开始标签了 { level = 1;//VF不赋值 } else if ((tag == 0xffffe0dd))//文件夹结束标签 { level = 0; } else { //FINFO("level:{$}", level); if (level == 1) { if ((tag == 0x7fe00010))//图像数据开始了 { nRet = fseek(f, VFlen, SEEK_CUR); if (nRet) { FERROR("fseek error! offset:{$}", ftell(f)); } } else { VF = getString(f, VFlen); } } else if (level == 0) { if ((tag == 0x7fe00010))//图像数据开始了 { FINFO("read image data begin nFrames:{$}", nFrames); ppData = (void**)malloc(sizeof(void*) * nFrames); for (int i = 0; i < nFrames; i++) { ppData[i] = (unsigned short*)malloc(sizeof(unsigned short) * height * width); fread(ppData[i], sizeof(unsigned short) * height * width, 1, f); } bLoaded = true; break; } else { VF = getString(f, VFlen); //--------针对特殊的tag的值的处理 //特别针对文件头信息处理 if (tag == 0x00020000) { //FINFO("tag == 0x00020000"); } else if (tag == 0x00020010)//传输语法 关系到后面的数据读取 { //FINFO("tag == 0x00020010 VF == {$}", VF); if (VF == "1.2.840.10008.1.2.1\0")//显示little { isLitteEndian = true; isExplicitVR = true; } else if (VF == "1.2.840.10008.1.2.2\0")//显示big { isLitteEndian = false; isExplicitVR = true; } else if (VF == "1.2.840.10008.1.2\0")//隐式little { isLitteEndian = true; isExplicitVR = false; } } else if (tag == 0x00080018) { SOPInstanceUID = VF; FINFO("tag == 0x00080018 VF == {$}, SOPInstanceUID:{$}", VF, SOPInstanceUID); } else if (tag == 0x00100010) { PatientName = VF; string str = PatientName; size_t pLeft = str.find('\\'); size_t pRight = str.find('.'); if (pRight > -1) { std::string ext = str.substr(pRight); if (ext == ".raw") PatientName = str.substr(pLeft + 1, pRight - pLeft - 1); } FINFO("tag == 0x00100010 VF == {$}, PatientName:{$}", VF, PatientName); } else if (tag == 0x00280004) { if (VF == "MONOCHROME2") bInverse = true; FINFO("tag == 0x00280004 VF == {$}", VF); } else if (tag == 0x00280008) { nFrames = str2int(VF); FINFO("tag == 0x00280008 VF == {$}, nFrames:{$}", VF, nFrames); } else if (tag == 0x00280010) { nRet = fseek(f, -2, SEEK_CUR); if (nRet) { FERROR("fseek error! offset:{$}", ftell(f)); } height = getShort16(f, isLitteEndian); FINFO("tag == 0x00280010 height == {$}", height); } else if (tag == 0x00280011) { nRet = fseek(f, -2, SEEK_CUR); if (nRet) { FERROR("fseek error! offset:{$}", ftell(f)); } width = getShort16(f, isLitteEndian); FINFO("tag == 0x00280011 width == {$}", width); } else if (tag == 0x00280100) { nRet = fseek(f, -2, SEEK_CUR); if (nRet) { FERROR("fseek error! offset:{$}", ftell(f)); } nBitsAllocated = getShort16(f, isLitteEndian); FINFO("tag == 0x00280100 nBitsAllocated == {$}", nBitsAllocated); } else if (tag == 0x00280102) { nRet = fseek(f, -2, SEEK_CUR); if (nRet) { FERROR("fseek error! offset:{$}", ftell(f)); } nHighBit = getShort16(f, isLitteEndian); if (nHighBit == 0) nHighBit = nBitsAllocated - 1; FINFO("tag == 0x00280102 nHighBit == {$}", nHighBit); } else if (tag == 0x00280103) { bSigned = str2int(VF) == 0 ? false : true; FINFO("tag == 0x00280103 VF == {$}, bSigned:{$}", VF, bSigned); } else if (tag == 0x00281050) { windowCenter = str2int(VF); FINFO("tag == 0x00281050 VF == {$}, windowCenter:{$}", VF, windowCenter); } else if (tag == 0x00281051) { windowWidth = str2int(VF); FINFO("tag == 0x00281051 VF == {$}, windowWidth:{$}", VF, windowWidth); } else if (tag == 0x00281052) { rescaleIntercept = str2double(VF); FINFO("tag == 0x00281052 VF == {$}, rescaleIntercept:{$}", VF, rescaleIntercept); } else if (tag == 0x00281053) { rescaleSlope = str2double(VF); FINFO("tag == 0x00281053 VF == {$}, rescaleSlope:{$}", VF, rescaleSlope); } } } // end level == 0 } } // while(decodingTags) fclose(f); nWidth = width, nHeight = height, nBits = nHighBit + 1, nWindowCenter = windowCenter, nWindowWidth = windowWidth; FINFO("load dcm over"); return true; } int getTag(FILE* f, bool isLitteEndian) { short groupWord = getShort16(f, isLitteEndian); short elementWord = getShort16(f, isLitteEndian); int tag = groupWord << 16 | elementWord; return tag; } std::string getVR(FILE* f) { return getString(f, 2); } char getByte8(FILE* f) { char b; fread(&b, sizeof(char), 1, f); return b; } short getShort16(FILE* f, bool isLitteEndian) { char b0 = getByte8(f); char b1 = getByte8(f); if (isLitteEndian) return (((b1 << 8) & 0x0000ff00) + (b0 & 0x000000ff)); else return (((b0 << 8) & 0x0000ff00) + (b1 & 0x000000ff)); } int getInt32(FILE* f, bool isLitteEndian) { char b0 = getByte8(f); char b1 = getByte8(f); char b2 = getByte8(f); char b3 = getByte8(f); if (isLitteEndian) return ((b3 << 24) + ((b2 << 16) & 0x00ff0000) + ((b1 << 8) & 0x0000ff00) + (b0 & 0x000000ff)); else return ((b0 << 24) + ((b1 << 16) & 0x00ff0000) + ((b2 << 8) & 0x0000ff00) + (b3 & 0x000000ff)); } std::string getString(FILE* f, int length) { if (length <= 0 || length > 65536 * 4) return std::string(""); char* buf = new char[length + 1]; size_t pos = 0; while (pos < length) { size_t count = fread(buf + pos, sizeof(char), (length - pos), f); if (count <= 0) break; pos += count; } buf[length] = '\0'; std::string str(buf); delete[] buf; return str; } int str2int(std::string s) { std::stringstream sstr(s); int num = 0; sstr >> num; return num; } double str2double(std::string s) { std::stringstream sstr(s); double num = 0; sstr >> num; return num; } std::string getInExplicitVR(int tag) { switch (tag) { case 0x00020000://文件元信息长度 return "UL"; break; case 0x00020010://传输语法 return "UI"; break; case 0x00020013://文件生成程序的标题 return "SH"; break; case 0x00080005://文本编码 return "CS"; break; case 0x00080008: return "CS"; break; case 0x00081032://成像时间 return "SQ"; break; case 0x00081111: return "SQ"; break; case 0x00080020://检查日期 return "DA"; break; case 0x00080060://成像仪器 return "CS"; break; case 0x00080070://成像仪厂商 return "LO"; break; case 0x00080080: return "LO"; break; case 0x00100010://病人姓名 return "PN"; break; case 0x00100020://病人id return "LO"; break; case 0x00100030://病人生日 return "DA"; break; case 0x00180060://电压 return "DS"; break; case 0x00181030://协议名 return "LO"; break; case 0x00181151: return "IS"; break; case 0x00200010://检查ID return "SH"; break; case 0x00200011://序列 return "IS"; break; case 0x00200012://成像编号 return "IS"; break; case 0x00200013://影像编号 return "IS"; break; case 0x00280002://像素采样1为灰度3为彩色 return "US"; break; case 0x00280004://图像模式MONOCHROME2为灰度 return "CS"; break; case 0x00280006://颜色值排列顺序 可能骨头重建那个的显示就是这个问题 return "US"; break; case 0x00280008://图像的帧数 return "IS"; break; case 0x00280010://row高 return "US"; break; case 0x00280011://col宽 return "US"; break; case 0x00280100://单个采样数据长度 return "US"; break; case 0x00280101://实际长度 return "US"; break; case 0x00280102://采样最大值 return "US"; break; case 0x00280103://像素数据类型 return "US"; break; case 0x00281050://窗位 return "DS"; break; case 0x00281051://窗宽 return "DS"; break; case 0x00281052: return "DS"; break; case 0x00281053: return "DS"; break; case 0x00400008://文件夹标签 return "SQ"; break; case 0x00400260://文件夹标签 return "SQ"; break; case 0x00400275://文件夹标签 return "SQ"; break; case 0x7fe00010://像素数据开始处 return "OW"; break; default: return "UN"; break; } } };