当前位置:   article > 正文

VTK读取DICOM文件根据InstanceNumber排序,生成为VTI格式的文件_seriesuid.begin()->c_str()

seriesuid.begin()->c_str()

 

  1. #include <itkImage.h>
  2. #include <itkGDCMImageIO.h>
  3. #include <itkImageSeriesReader.h>
  4. #include <itkGDCMSeriesFileNames.h>
  5. #include <itkImageToVTKImageFilter.h>
  6. #include <vtkCamera.h>
  7. #include <vtkProperty.h>
  8. #include <vtkMatrix4x4.h>
  9. #include <vtkImageData.h>
  10. #include <vtkPNGWriter.h>
  11. #include <vtkImageData.h>
  12. #include <vtkJPEGWriter.h>
  13. #include <vtkImageActor.h>
  14. #include <vtkLineSource.h>
  15. #include <vtkSmartPointer.h>
  16. #include <vtkImageViewer2.h>
  17. #include <vtkImageReslice.h>
  18. #include <vtkDataSetMapper.h>
  19. #include <vtkXMLImageDataWriter.h>
  20. #include <vtkInteractorStyleImage.h>
  21. #include <string>
  22. #include <vector>
  23. #include <cstdarg>
  24. #if defined(_WIN32)
  25. #include <io.h>
  26. #include <direct.h> // _mkdir
  27. #else
  28. #include <sys/stat.h> // stat
  29. #include <errno.h> // errno, ENOENT, EEXIST
  30. #include <stdio.h>
  31. #endif
  32. bool MakePath(const std::string& path)
  33. {
  34. #if defined(_WIN32)
  35. int ret = _mkdir(path.c_str());
  36. #else
  37. mode_t mode = 0755;
  38. int ret = mkdir(path.c_str(), mode);
  39. #endif
  40. if (ret == 0)
  41. return true;
  42. switch (errno)
  43. {
  44. case ENOENT:
  45. // parent didn't exist, try to create it
  46. {
  47. size_t pos = path.find_last_of('/');
  48. if (pos == std::string::npos)
  49. #if defined(_WIN32)
  50. pos = path.find_last_of('\\');
  51. if (pos == std::string::npos)
  52. #endif
  53. return false;
  54. if (!MakePath(path.substr(0, pos)))
  55. return false;
  56. }
  57. // now, try to create again
  58. #if defined(_WIN32)
  59. return 0 == _mkdir(path.c_str());
  60. #else
  61. return 0 == mkdir(path.c_str(), mode);
  62. #endif
  63. //case EEXIST:
  64. // // done!
  65. // return IsDirExist(path);
  66. default:
  67. return false;
  68. }
  69. }
  70. /**
  71. * @brief GetFileNames 利用寻找文件夹里所有dicom文件(跟后缀无关)
  72. * @param dicom_file_path 输入路径(文件)
  73. * @param file_names dicom_file_path同级文件所有dicom类型文件
  74. * @return
  75. */
  76. using FileNamesContainer = std::vector< std::string >;
  77. bool GetFileNames(const std::string &dicom_file_path,
  78. FileNamesContainer &file_names) {
  79. if (dicom_file_path.empty()) {
  80. return false;
  81. }
  82. //QFileInfo file_info(dicom_file_path);
  83. std::string extension = ".dcm";// file_info.path();
  84. std::string series_identifier;
  85. using NamesGeneratorType = itk::GDCMSeriesFileNames;
  86. using SeriesIdContainer = std::vector< std::string >;
  87. NamesGeneratorType::Pointer name_generator = NamesGeneratorType::New();
  88. name_generator->SetUseSeriesDetails(true);
  89. //name_generator->SetDirectory(extension.toLocal8Bit().data());
  90. std::string folder = dicom_file_path.substr(0, dicom_file_path.find_last_of("\\"));
  91. name_generator->SetDirectory(folder);
  92. const SeriesIdContainer &seriesUID = name_generator->GetSeriesUIDs();
  93. auto seriesItr = seriesUID.begin();
  94. auto seriesEnd = seriesUID.end();
  95. while (seriesItr != seriesEnd) {
  96. series_identifier = seriesItr->c_str();
  97. file_names = name_generator->GetFileNames(series_identifier);
  98. ++seriesItr;
  99. }
  100. return true;
  101. }
  102. /**
  103. * @brief ReadDicoms/ReadDicom 读取文件(3维/2维)
  104. */
  105. typedef signed short InputPixelType;
  106. typedef itk::Image< InputPixelType, 2 > InputImageType;
  107. typedef itk::Image< InputPixelType, 3 > InputImageTypes;
  108. bool ReadDicoms(const FileNamesContainer &file_names,
  109. InputImageTypes::Pointer &image) {
  110. typedef itk::ImageSeriesReader<InputImageTypes> ReaderType;
  111. using ImageIOType = itk::GDCMImageIO;
  112. ReaderType::Pointer reader = ReaderType::New();
  113. ImageIOType::Pointer dicomIO = ImageIOType::New();
  114. reader->SetImageIO(dicomIO);
  115. reader->SetFileNames(file_names);
  116. try {
  117. reader->Update();
  118. }
  119. catch (itk::ExceptionObject &) {
  120. return false;
  121. }
  122. image = reader->GetOutput();
  123. return true;
  124. }
  125. bool ReadDicom(const std::string &file_name,
  126. InputImageType::Pointer &image) {
  127. typedef itk::ImageFileReader<InputImageType> ReaderType;
  128. ReaderType::Pointer reader = ReaderType::New();
  129. typedef itk::GDCMImageIO ImageIOType;
  130. ImageIOType::Pointer gdcmImageIO = ImageIOType::New();
  131. reader->SetFileName(file_name);
  132. reader->SetImageIO(gdcmImageIO);
  133. try {
  134. reader->Update();
  135. }
  136. catch (itk::ExceptionObject &) {
  137. return false;
  138. }
  139. image = reader->GetOutput();
  140. return true;
  141. }
  142. void CopySingleFile(const std::string& input, const std::string& output)
  143. {
  144. #include <fstream>
  145. std::ifstream src(input, std::ios::binary);
  146. std::ofstream dst(output, std::ios::binary);
  147. dst << src.rdbuf();
  148. }
  149. inline std::string Trim(std::string& str)
  150. {
  151. str.erase(0, str.find_first_not_of(' ')); //prefixing spaces
  152. str.erase(str.find_last_not_of(' ') + 1); //surfixing spaces
  153. return str;
  154. }
  155. //missing string printf
  156. //this is safe and convenient but not exactly efficient
  157. inline std::string Format(const char* fmt, ...)
  158. {
  159. int size = 512;
  160. char* buffer = 0;
  161. buffer = new char[size];
  162. va_list vl;
  163. va_start(vl, fmt);
  164. int nsize = vsnprintf(buffer, size, fmt, vl);
  165. if (size <= nsize) { //fail delete buffer and try again
  166. delete[] buffer;
  167. buffer = 0;
  168. buffer = new char[nsize + 1]; //+1 for /0
  169. nsize = vsnprintf(buffer, size, fmt, vl);
  170. }
  171. std::string ret(buffer);
  172. va_end(vl);
  173. delete[] buffer;
  174. return ret;
  175. }
  176. /**
  177. * @brief CopyDicom 拷贝dicom到指定目录,根据Slice Location、Acquisition Number排序
  178. * @param dicom_path 输入路径
  179. * @param list 记录所有输出文件路径
  180. * @param out_paths 输出路径(拷贝)
  181. * @return
  182. */
  183. bool CopyDicom(const std::string &dicom_path,
  184. std::vector<std::string> &list,
  185. const std::string &out_paths) {
  186. // 读入dcm
  187. FileNamesContainer file_names;
  188. if (!GetFileNames(dicom_path, file_names)) {
  189. return false;
  190. }
  191. std::vector<std::string>::iterator the_iterator;
  192. for (the_iterator = file_names.begin(); the_iterator
  193. != file_names.end(); the_iterator++)
  194. {
  195. // 记录tags
  196. InputImageType::Pointer image = InputImageType::New();
  197. ReadDicom(the_iterator->c_str(), image);
  198. typedef itk::MetaDataDictionary DictionaryType;
  199. using MetaDataStringType = itk::MetaDataObject<std::string>;
  200. DictionaryType &dictionary = image->GetMetaDataDictionary();
  201. std::map<std::string, std::string> key_list;
  202. for (auto ite = dictionary.Begin(); ite != dictionary.End(); ++ite)
  203. {
  204. std::string id = (ite->first);
  205. itk::MetaDataObjectBase::Pointer entry = ite->second;
  206. MetaDataStringType::ConstPointer entry_value =
  207. dynamic_cast<const MetaDataStringType *>(ite->second.GetPointer());
  208. std::string key_string;
  209. itk::GDCMImageIO::GetLabelFromTag(id.c_str(), key_string);
  210. std::string key = (key_string);
  211. std::string value = (entry_value->GetMetaDataObjectValue());
  212. itk::EncapsulateMetaData<std::string>(dictionary, key_string, "value");
  213. key_list.insert(std::pair<std::string, std::string>(key, value));
  214. }
  215. // 根据Instance Number重命名拷贝文件
  216. std::string out_path = out_paths;// +key_list["Slice Location"];
  217. MakePath(out_path);
  218. // list << out_path;
  219. //(0020, 0013) IS 23 # 1, 2 Instance Number
  220. //std::string InstanceNumber = Format("%5d", atoi(Trim(key_list["Instance Number"]).c_str()));
  221. char str[7];
  222. snprintf(str, 7, "%04d", atoi(Trim(key_list["Instance Number"]).c_str()));
  223. out_path += "/" + std::string(str) + ".dcm";
  224. std::cout << out_path << "\n";
  225. CopySingleFile(the_iterator->c_str(), out_path);
  226. list.push_back(out_path);
  227. }
  228. return true;
  229. }
  230. /**
  231. * @brief GenerateVti 把输入路径里所有dcm写出为vti
  232. * @param path 输入dcm路径
  233. */
  234. void GenerateVti(std::vector<std::string> file_names)
  235. {
  236. vtkNew<vtkImageData> imagedata;
  237. // 读入dcm
  238. //FileNamesContainer file_names;
  239. InputImageTypes::Pointer input_image = InputImageTypes::New();
  240. //GetFileNames((path + "/1.dcm"), file_names);
  241. ReadDicoms(file_names, input_image);
  242. typedef itk::ImageToVTKImageFilter< InputImageTypes> itkTovtkFilterType;
  243. itkTovtkFilterType::Pointer itkTovtkImageFilter = itkTovtkFilterType::New();
  244. itkTovtkImageFilter->SetInput(input_image);
  245. itkTovtkImageFilter->Update();
  246. imagedata->DeepCopy(itkTovtkImageFilter->GetOutput());
  247. // 写出vti
  248. vtkNew<vtkXMLImageDataWriter> writer;
  249. writer->SetInputData(imagedata);
  250. writer->SetFileName("floor.vti");
  251. writer->Write();
  252. }
  253. int main(int, char *[])
  254. {
  255. std::string in_paths = "input/000001.dcm";
  256. std::string out_paths = "output/";
  257. std::vector<std::string> list;// 目标路径
  258. // 拷贝文件
  259. CopyDicom(in_paths, list, out_paths);
  260. // vti
  261. GenerateVti(list);
  262. return 0;
  263. }

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/520694
推荐阅读
相关标签
  

闽ICP备14008679号