dcm.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /*
  2. Example:
  3. dcm d;
  4. d.Load(filename.c_str());
  5. WORD *pImg = (WORD*)(d.ppData[i]);
  6. memcpy(pInArray[ 1 ], (WORD*)(d.ppData[i]), d.nHeight * d.nWidth * sizeof(WORD));
  7. */
  8. #pragma once
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string>
  12. #include <sstream> //使用stringstream需要引入这个头文件
  13. using namespace std;
  14. //extern Log4CPP::Logger* mLog::gLogger;
  15. class dcm
  16. {
  17. public:
  18. int nWidth, nHeight, nBits, nFrames, nWindowCenter, nWindowWidth;
  19. void ** ppData;
  20. string PatientName, SOPInstanceUID;
  21. int filesize;
  22. bool bLoaded;
  23. dcm() : nWidth(0), nHeight(0), nBits(0), ppData(0), bLoaded(false)
  24. {
  25. };
  26. ~dcm()
  27. {
  28. Destroy();
  29. }
  30. void Destroy()
  31. {
  32. if (ppData != NULL)
  33. {
  34. for (int i = 0; i < nFrames; i++)
  35. {
  36. if (ppData[i] != NULL)
  37. {
  38. free(ppData[i]);
  39. ppData[i] = NULL;
  40. }
  41. }
  42. free(ppData);
  43. ppData = NULL;
  44. }
  45. nWidth = nHeight = nBits = 0;
  46. bLoaded = false;
  47. };
  48. unsigned short & operator()(int h, int w, int f = 0) { return ((unsigned short*)(ppData[f]))[h * nWidth + w]; }
  49. //unsigned short & operator()(int index, int f = 0) { return ((unsigned short*)(ppData[f]))[index]; }
  50. void Load_raw_file(const char* filename)
  51. {
  52. char tmp[64] = { 0 }, str[32] = { 0 };
  53. char *p1, *p2;
  54. strncpy(tmp, filename, sizeof(tmp) - 1);
  55. tmp[strlen(filename) - 4] = '\0';
  56. p2 = strrchr(tmp, '_');
  57. int loc2 = p2 - tmp;
  58. strncpy(str, p2 + 1, sizeof(str) - 1);
  59. nHeight = atoi(str);
  60. tmp[loc2] = '\0';
  61. p1 = strrchr(tmp, '_');
  62. int loc1 = p1 - tmp;
  63. strncpy(str, p1 + 1, sizeof(str) - 1);
  64. nWidth = atoi(str);
  65. nBits = 16;
  66. nFrames = 1;
  67. ppData = (void**)malloc(sizeof(void*) * nFrames);
  68. ppData[0] = (unsigned short*)malloc(sizeof(unsigned short) * nHeight * nWidth);
  69. FILE* fid = fopen(filename, "rb");
  70. if (fid != NULL) {
  71. size_t nBytes = fread(ppData[0], sizeof(unsigned short), nHeight * nWidth, fid);
  72. fclose(fid);
  73. bLoaded = true;
  74. }
  75. else {
  76. // 处理文件打开失败的情况
  77. bLoaded = false;
  78. // 可以在这里添加错误处理代码,如释放已分配的内存
  79. if (ppData != NULL) {
  80. free(ppData[0]);
  81. free(ppData);
  82. ppData = NULL;
  83. }
  84. }
  85. bLoaded = true;
  86. }
  87. bool Load(const char* filename)
  88. {
  89. bool isLitteEndian = false;//是否小字节序(小端在前 、大端在前)
  90. bool isExplicitVR = false;//有无VR
  91. // key info for image data
  92. int height = 0, width = 0, nHighBit = 0, nBitsAllocated = 0;
  93. bool bSigned = false;
  94. int windowCenter = 0, windowWidth = 0;
  95. double rescaleIntercept, rescaleSlope;
  96. bool bInverse = false;
  97. nFrames = 1;
  98. int nRet = 0;
  99. isLitteEndian = true;//是否小字节序(小端在前 、大端在前)
  100. isExplicitVR = true;//有无VR
  101. // read tag,VR,VF...
  102. int tag = 0;
  103. std::string VR, VF;
  104. int VFlen = 0;
  105. // info folder
  106. bool endDir = false;
  107. int level = 0;
  108. FILE *f = 0;
  109. f = fopen(filename, "rb");
  110. if (f == NULL)
  111. {
  112. FERROR("open %s fail!", filename);
  113. return false;
  114. }
  115. fseek(f, 0L, SEEK_END); /* 定位到文件末尾 */
  116. filesize = ftell(f); /* 得到文件大小 */
  117. FINFO("file size:{$}", filesize);
  118. fseek(f, 0L, SEEK_SET); /* 定位到文件开头 */
  119. fseek(f, 128, SEEK_SET);
  120. if (!(getString(f, 4) == "DICM"))
  121. {
  122. fclose(f);
  123. FERROR("getString fail!");
  124. return false;
  125. }
  126. while (true)
  127. {
  128. tag = getTag(f, isLitteEndian);
  129. if (tag == 0)
  130. {
  131. int len = ftell(f);
  132. FINFO("offset length:{$}",len);
  133. fclose(f);
  134. FERROR("getTag fail!");
  135. return false;
  136. }
  137. // getVR
  138. if (isExplicitVR == false)
  139. {
  140. VR = getInExplicitVR(tag);
  141. VFlen = getInt32(f, isLitteEndian);
  142. }
  143. else
  144. {
  145. if ((tag & 0x000f0000) == 0x00020000)//文件头 特殊情况
  146. {
  147. VR = getVR(f);
  148. if (VR == "OB" || VR == "OW" || VR == "SQ" || VR == "OF" || VR == "UT" || VR == "UN")
  149. {
  150. nRet = fseek(f, 2, SEEK_CUR);
  151. if (nRet)
  152. {
  153. FERROR("fseek error! offset:{$}", ftell(f));
  154. }
  155. VFlen = getInt32(f, isLitteEndian);
  156. }
  157. else
  158. {
  159. VFlen = getShort16(f, isLitteEndian);
  160. }
  161. //FINFO("111 VR:{$},VFlen:{$}", VR, VFlen);
  162. }
  163. else if (tag == 0xffffe000 || tag == 0xffffe00d || tag == 0xffffe0dd)//文件夹标签
  164. {
  165. VR = "**";
  166. VFlen = getInt32(f, isLitteEndian);
  167. //FINFO("222 VR:{$},VFlen:{$}", VR, VFlen);
  168. }
  169. else
  170. {
  171. VR = getVR(f);
  172. if (VR == "OB" || VR == "OW" || VR == "SQ" || VR == "OF" || VR == "UT" || VR == "UN")
  173. {
  174. nRet = fseek(f, 2, SEEK_CUR);
  175. if (nRet)
  176. {
  177. FERROR("fseek error! offset:{$}", ftell(f));
  178. }
  179. VFlen = getInt32(f, isLitteEndian);
  180. }
  181. else
  182. {
  183. VFlen = getShort16(f, isLitteEndian);
  184. }
  185. //FINFO("333 VR:{$},VFlen:{$}", VR, VFlen);
  186. }
  187. }
  188. // getVF
  189. //判断是否应该读取VF 以何种方式读取VF
  190. //--------------这些都是在读取VF一步被阻断的情况
  191. if ((tag == 0xffffe000))//遇到文件夹开始标签了
  192. {
  193. level = 1;//VF不赋值
  194. }
  195. else if ((tag == 0xffffe0dd))//文件夹结束标签
  196. {
  197. level = 0;
  198. }
  199. else
  200. {
  201. //FINFO("level:{$}", level);
  202. if (level == 1)
  203. {
  204. if ((tag == 0x7fe00010))//图像数据开始了
  205. {
  206. nRet = fseek(f, VFlen, SEEK_CUR);
  207. if (nRet)
  208. {
  209. FERROR("fseek error! offset:{$}", ftell(f));
  210. }
  211. }
  212. else
  213. {
  214. VF = getString(f, VFlen);
  215. }
  216. }
  217. else if (level == 0)
  218. {
  219. if ((tag == 0x7fe00010))//图像数据开始了
  220. {
  221. FINFO("read image data begin nFrames:{$}", nFrames);
  222. ppData = (void**)malloc(sizeof(void*) * nFrames);
  223. for (int i = 0; i < nFrames; i++)
  224. {
  225. ppData[i] = (unsigned short*)malloc(sizeof(unsigned short) * height * width);
  226. fread(ppData[i], sizeof(unsigned short) * height * width, 1, f);
  227. }
  228. bLoaded = true;
  229. break;
  230. }
  231. else
  232. {
  233. VF = getString(f, VFlen);
  234. //--------针对特殊的tag的值的处理
  235. //特别针对文件头信息处理
  236. if (tag == 0x00020000)
  237. {
  238. //FINFO("tag == 0x00020000");
  239. }
  240. else if (tag == 0x00020010)//传输语法 关系到后面的数据读取
  241. {
  242. //FINFO("tag == 0x00020010 VF == {$}", VF);
  243. if (VF == "1.2.840.10008.1.2.1\0")//显示little
  244. {
  245. isLitteEndian = true;
  246. isExplicitVR = true;
  247. }
  248. else if (VF == "1.2.840.10008.1.2.2\0")//显示big
  249. {
  250. isLitteEndian = false;
  251. isExplicitVR = true;
  252. }
  253. else if (VF == "1.2.840.10008.1.2\0")//隐式little
  254. {
  255. isLitteEndian = true;
  256. isExplicitVR = false;
  257. }
  258. }
  259. else if (tag == 0x00080018)
  260. {
  261. SOPInstanceUID = VF;
  262. FINFO("tag == 0x00080018 VF == {$}, SOPInstanceUID:{$}", VF, SOPInstanceUID);
  263. }
  264. else if (tag == 0x00100010)
  265. {
  266. PatientName = VF;
  267. string str = PatientName;
  268. size_t pLeft = str.find('\\');
  269. size_t pRight = str.find('.');
  270. if (pRight > -1)
  271. {
  272. std::string ext = str.substr(pRight);
  273. if (ext == ".raw")
  274. PatientName = str.substr(pLeft + 1, pRight - pLeft - 1);
  275. }
  276. FINFO("tag == 0x00100010 VF == {$}, PatientName:{$}", VF, PatientName);
  277. }
  278. else if (tag == 0x00280004)
  279. {
  280. if (VF == "MONOCHROME2")
  281. bInverse = true;
  282. FINFO("tag == 0x00280004 VF == {$}", VF);
  283. }
  284. else if (tag == 0x00280008)
  285. {
  286. nFrames = str2int(VF);
  287. FINFO("tag == 0x00280008 VF == {$}, nFrames:{$}", VF, nFrames);
  288. }
  289. else if (tag == 0x00280010)
  290. {
  291. nRet = fseek(f, -2, SEEK_CUR);
  292. if (nRet)
  293. {
  294. FERROR("fseek error! offset:{$}", ftell(f));
  295. }
  296. height = getShort16(f, isLitteEndian);
  297. FINFO("tag == 0x00280010 height == {$}", height);
  298. }
  299. else if (tag == 0x00280011)
  300. {
  301. nRet = fseek(f, -2, SEEK_CUR);
  302. if (nRet)
  303. {
  304. FERROR("fseek error! offset:{$}", ftell(f));
  305. }
  306. width = getShort16(f, isLitteEndian);
  307. FINFO("tag == 0x00280011 width == {$}", width);
  308. }
  309. else if (tag == 0x00280100)
  310. {
  311. nRet = fseek(f, -2, SEEK_CUR);
  312. if (nRet)
  313. {
  314. FERROR("fseek error! offset:{$}", ftell(f));
  315. }
  316. nBitsAllocated = getShort16(f, isLitteEndian);
  317. FINFO("tag == 0x00280100 nBitsAllocated == {$}", nBitsAllocated);
  318. }
  319. else if (tag == 0x00280102)
  320. {
  321. nRet = fseek(f, -2, SEEK_CUR);
  322. if (nRet)
  323. {
  324. FERROR("fseek error! offset:{$}", ftell(f));
  325. }
  326. nHighBit = getShort16(f, isLitteEndian);
  327. if (nHighBit == 0)
  328. nHighBit = nBitsAllocated - 1;
  329. FINFO("tag == 0x00280102 nHighBit == {$}", nHighBit);
  330. }
  331. else if (tag == 0x00280103)
  332. {
  333. bSigned = str2int(VF) == 0 ? false : true;
  334. FINFO("tag == 0x00280103 VF == {$}, bSigned:{$}", VF, bSigned);
  335. }
  336. else if (tag == 0x00281050)
  337. {
  338. windowCenter = str2int(VF);
  339. FINFO("tag == 0x00281050 VF == {$}, windowCenter:{$}", VF, windowCenter);
  340. }
  341. else if (tag == 0x00281051)
  342. {
  343. windowWidth = str2int(VF);
  344. FINFO("tag == 0x00281051 VF == {$}, windowWidth:{$}", VF, windowWidth);
  345. }
  346. else if (tag == 0x00281052)
  347. {
  348. rescaleIntercept = str2double(VF);
  349. FINFO("tag == 0x00281052 VF == {$}, rescaleIntercept:{$}", VF, rescaleIntercept);
  350. }
  351. else if (tag == 0x00281053)
  352. {
  353. rescaleSlope = str2double(VF);
  354. FINFO("tag == 0x00281053 VF == {$}, rescaleSlope:{$}", VF, rescaleSlope);
  355. }
  356. }
  357. } // end level == 0
  358. }
  359. } // while(decodingTags)
  360. fclose(f);
  361. nWidth = width, nHeight = height, nBits = nHighBit + 1, nWindowCenter = windowCenter, nWindowWidth = windowWidth;
  362. FINFO("load dcm over");
  363. return true;
  364. }
  365. int getTag(FILE* f, bool isLitteEndian) {
  366. short groupWord = getShort16(f, isLitteEndian);
  367. short elementWord = getShort16(f, isLitteEndian);
  368. int tag = groupWord << 16 | elementWord;
  369. return tag;
  370. }
  371. std::string getVR(FILE* f) {
  372. return getString(f, 2);
  373. }
  374. char getByte8(FILE* f) {
  375. char b;
  376. fread(&b, sizeof(char), 1, f);
  377. return b;
  378. }
  379. short getShort16(FILE* f, bool isLitteEndian) {
  380. char b0 = getByte8(f);
  381. char b1 = getByte8(f);
  382. if (isLitteEndian)
  383. return (((b1 << 8) & 0x0000ff00) + (b0 & 0x000000ff));
  384. else
  385. return (((b0 << 8) & 0x0000ff00) + (b1 & 0x000000ff));
  386. }
  387. int getInt32(FILE* f, bool isLitteEndian) {
  388. char b0 = getByte8(f);
  389. char b1 = getByte8(f);
  390. char b2 = getByte8(f);
  391. char b3 = getByte8(f);
  392. if (isLitteEndian)
  393. return ((b3 << 24) + ((b2 << 16) & 0x00ff0000) + ((b1 << 8) & 0x0000ff00) + (b0 & 0x000000ff));
  394. else
  395. return ((b0 << 24) + ((b1 << 16) & 0x00ff0000) + ((b2 << 8) & 0x0000ff00) + (b3 & 0x000000ff));
  396. }
  397. std::string getString(FILE* f, int length) {
  398. if (length <= 0 || length > 65536 * 4) return std::string("");
  399. char* buf = new char[length + 1];
  400. size_t pos = 0;
  401. while (pos < length)
  402. {
  403. size_t count = fread(buf + pos, sizeof(char), (length - pos), f);
  404. if (count <= 0) break;
  405. pos += count;
  406. }
  407. buf[length] = '\0';
  408. std::string str(buf);
  409. delete[] buf;
  410. return str;
  411. }
  412. int str2int(std::string s) {
  413. std::stringstream sstr(s);
  414. int num = 0;
  415. sstr >> num;
  416. return num;
  417. }
  418. double str2double(std::string s) {
  419. std::stringstream sstr(s);
  420. double num = 0;
  421. sstr >> num;
  422. return num;
  423. }
  424. std::string getInExplicitVR(int tag)
  425. {
  426. switch (tag)
  427. {
  428. case 0x00020000://文件元信息长度
  429. return "UL";
  430. break;
  431. case 0x00020010://传输语法
  432. return "UI";
  433. break;
  434. case 0x00020013://文件生成程序的标题
  435. return "SH";
  436. break;
  437. case 0x00080005://文本编码
  438. return "CS";
  439. break;
  440. case 0x00080008:
  441. return "CS";
  442. break;
  443. case 0x00081032://成像时间
  444. return "SQ";
  445. break;
  446. case 0x00081111:
  447. return "SQ";
  448. break;
  449. case 0x00080020://检查日期
  450. return "DA";
  451. break;
  452. case 0x00080060://成像仪器
  453. return "CS";
  454. break;
  455. case 0x00080070://成像仪厂商
  456. return "LO";
  457. break;
  458. case 0x00080080:
  459. return "LO";
  460. break;
  461. case 0x00100010://病人姓名
  462. return "PN";
  463. break;
  464. case 0x00100020://病人id
  465. return "LO";
  466. break;
  467. case 0x00100030://病人生日
  468. return "DA";
  469. break;
  470. case 0x00180060://电压
  471. return "DS";
  472. break;
  473. case 0x00181030://协议名
  474. return "LO";
  475. break;
  476. case 0x00181151:
  477. return "IS";
  478. break;
  479. case 0x00200010://检查ID
  480. return "SH";
  481. break;
  482. case 0x00200011://序列
  483. return "IS";
  484. break;
  485. case 0x00200012://成像编号
  486. return "IS";
  487. break;
  488. case 0x00200013://影像编号
  489. return "IS";
  490. break;
  491. case 0x00280002://像素采样1为灰度3为彩色
  492. return "US";
  493. break;
  494. case 0x00280004://图像模式MONOCHROME2为灰度
  495. return "CS";
  496. break;
  497. case 0x00280006://颜色值排列顺序 可能骨头重建那个的显示就是这个问题
  498. return "US";
  499. break;
  500. case 0x00280008://图像的帧数
  501. return "IS";
  502. break;
  503. case 0x00280010://row高
  504. return "US";
  505. break;
  506. case 0x00280011://col宽
  507. return "US";
  508. break;
  509. case 0x00280100://单个采样数据长度
  510. return "US";
  511. break;
  512. case 0x00280101://实际长度
  513. return "US";
  514. break;
  515. case 0x00280102://采样最大值
  516. return "US";
  517. break;
  518. case 0x00280103://像素数据类型
  519. return "US";
  520. break;
  521. case 0x00281050://窗位
  522. return "DS";
  523. break;
  524. case 0x00281051://窗宽
  525. return "DS";
  526. break;
  527. case 0x00281052:
  528. return "DS";
  529. break;
  530. case 0x00281053:
  531. return "DS";
  532. break;
  533. case 0x00400008://文件夹标签
  534. return "SQ";
  535. break;
  536. case 0x00400260://文件夹标签
  537. return "SQ";
  538. break;
  539. case 0x00400275://文件夹标签
  540. return "SQ";
  541. break;
  542. case 0x7fe00010://像素数据开始处
  543. return "OW";
  544. break;
  545. default:
  546. return "UN";
  547. break;
  548. }
  549. }
  550. };