123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601 |
- /*
- 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 <stdio.h>
- #include <stdlib.h>
- #include <string>
- #include <sstream> //使用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;
- }
- }
- };
|