最近在整理与回顾刚加入实验室所学的相关知识,那会主要是对DICOM这个医疗图像进行相应的研究,之前有一篇博客已经讲述了一些有关DICOM的基本知识,今天这篇博客就让我们了解一下如何将Dicom文件转为mhd,raw文件格式。
一、将Dicom文件转mhd,raw文件格式的原因
医学图像通常是通过dicom文件格式进行存储的,但为了便于读取和使用也常常将其转化为:每个病人一个mhd文件和一个同名的raw文件的格式,mhd即meta header data,数据头部信息,raw存储了像素信息。如下图所示:
二、利用python+SimpleITK完成上述过程的转换
其中mhd文件存储了dicom的头部信息,由于头部信息很多生成mhd的方法有所不同,所以这里展示了通过ITK(ITK是美国国家卫生院下属的国立医学图书馆开发的一款医学图像处理软件包,是一个开源的、跨平台的影像分析扩展软件工具。)产生mhd文件的文件内容(利用写字板打开),有以下头部信息:
以下为实现的代码,附着详细的代码注释:
复制代码
1 import cv2
2 import os
3 import pydicom
4 import numpy
5 import SimpleITK
6
7 # 路径和列表声明
8 # 与python文件同一个目录下的文件夹,存储dicom文件,该文件路径最好不要含有中文
9 PathDicom = "D:/dicom_image/V"
10 # 与python文件同一个目录下的文件夹,用来存储mhd文件和raw文件,该文件路径最好不要含有中文
11 SaveRawDicom = "D:/dicom_image/V/SaveRaw"
12 lstFilesDCM = []
13
14 # 将PathDicom文件夹下的dicom文件地址读取到lstFilesDCM中
15 for dirName, subdirList, fileList in os.walk(PathDicom):
16 for filename in fileList:
17 if ".dcm" in filename.lower(): # 判断文件是否为dicom文件
18 print(filename)
19 lstFilesDCM.append(os.path.join(dirName, filename)) # 加入到列表中
20
21 # 第一步:将第一张图片作为参考图片,并认为所有图片具有相同维度
22 RefDs = pydicom.read_file(lstFilesDCM[0]) # 读取第一张dicom图片
23
24 # 第二步:得到dicom图片所组成3D图片的维度
25 ConstPixelDims = (int(RefDs.Rows), int(RefDs.Columns), len(lstFilesDCM)) # ConstPixelDims是一个元组
26
27 # 第三步:得到x方向和y方向的Spacing并得到z方向的层厚
28 ConstPixelSpacing = (float(RefDs.PixelSpacing[0]), float(RefDs.PixelSpacing[1]), float(RefDs.SliceThickness))
29
30 # 第四步:得到图像的原点
31 Origin = RefDs.ImagePositionPatient
32
33 # 根据维度创建一个numpy的三维数组,并将元素类型设为:pixel_array.dtype
34 ArrayDicom = numpy.zeros(ConstPixelDims, dtype=RefDs.pixel_array.dtype) # array is a numpy array
35
36 # 第五步:遍历所有的dicom文件,读取图像数据,存放在numpy数组中
37 i = 0
38 for filenameDCM in lstFilesDCM:
39 ds = pydicom.read_file(filenameDCM)
40 ArrayDicom[:, :, lstFilesDCM.index(filenameDCM)] = ds.pixel_array
41 cv2.imwrite("out_" + str(i) + ".png", ArrayDicom[:, :, lstFilesDCM.index(filenameDCM)])
42 i += 1
43
44 # 第六步:对numpy数组进行转置,即把坐标轴(x,y,z)变换为(z,y,x),这样是dicom存储文件的格式,即第一个维度为z轴便于图片堆叠
45 ArrayDicom = numpy.transpose(ArrayDicom, (2, 0, 1))
46
47 # 第七步:将现在的numpy数组通过SimpleITK转化为mhd和raw文件
48 sitk_img = SimpleITK.GetImageFromArray(ArrayDicom, isVector=False)
49 sitk_img.SetSpacing(ConstPixelSpacing)
50 sitk_img.SetOrigin(Origin)
51 SimpleITK.WriteImage(sitk_img, os.path.join(SaveRawDicom, "sample" + ".mhd"))public class DispatcherServlet extends HttpServlet {
private Properties contextConfigProperties = new Properties();
private List<String> classNames = new ArrayList<>();
private Map<String, Object> ioc = new HashMap<String, Object>();
private Map<String, Method> handlerMappings = new HashMap<>();
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
dispatcher(req,resp);
} catch (Exception e) {
resp.getWriter().write("500 Server has an error"+Arrays.toString(e.getStackTrace()));
}
}
private void dispatcher(HttpServletRequest req, HttpServletResponse resp) throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (this.handlerMappings.isEmpty()) {
return;
}
String url = req.getRequestURI();
String contextPath =baihuiyulegw.com req.getContextPath();
url.replace(contextPath, ""www.yunsengyule.com).replaceAll("/+", "/");
if (!this.handlerMappings.containsKey(url)) {
resp.getWriter().write("404 Page Not Found! ");
return;
}
Method method = this.handlerMappings.get(url);
Map<String,String[]> parameterMap = req.getParameterMap();
String beanName = this.lowerFirstLetter(method.getDeclaringClass().getSimpleName());
Object obj = this.ioc.get(beanName);
if (!parameterMap.containsKey(www.mmingyLgw.com"name")) {
resp.getWriter().write("handerMapping Not Found!");
return;
}
method.invoke(obj, new Object[] {req,resp,parameterMap.get("name")[0]});
}
@Override
public void init(ServletConfig config) throws ServletException {
//加载配置
loadConfig(config.getInitParameter("contextConfigLocation"));
//扫描指定包下的所有类
scannerClass(this.contextConfigProperties.getProperty("scanPackage"));
//初始化容器
initIoc();
//自动注入
autoWiredInstance();
//初始化处理映射
initHanderMapping(www.yongshi123.cn);
System.out.println("mvc init over...");
}
private void initHanderMapping() {
if (this.ioc.isEmpty()) {
return;
}
try {
for (Map.Entry<String, Object> en : this.ioc.entrySet()) {
boolean present = en.getValue().getClass().isAnnotationPresent(Controller.class);
if (present) {
StringBuffer baseUrl = new StringBuffer(www.mumingyue.cn);
RequestMapping requestMapping = en.getValue(www.fengshen157.com/).getClass().getAnnotation(RequestMapping.class);
baseUrl.append(requestMapping.value());
Method[] methods www.douniu2.cc= en.getValue().getClass().getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(RequestMapping.class)) {
RequestMapping mapping = method.getAnnotation(RequestMapping.class);
String fullUrl = ("/"+baseUrl.append(www.tscdeLu.cn"/").append(mapping.value().trim()).toString()).replaceAll("/+", "/");
this.handlerMappings.put(fullUrl, method);
复制代码