CT影像数据(nrrd文件和dicm文件)的读取和预处理
說點題外話:最近參加了一個學院老師的創新項目(其實早就參加了,咸魚劃水到了現在才動 ),內容是使用機器學習算法對腎癌CT影像數據進行預測,所以就有了第一步–數據預處理(給自己挖了一個大大的坑 ),就一個數據預處理代碼我寫了一個多星期,我也是服了我自己了。數據保密,大家就不要想找我要數據了,我是不會給的,這個博客只是用來記錄一下我的慘淡經歷。
數據處理過程中遇到的坑:
1、由于自己第一次接觸醫學,第一次用代碼實現CT數據預處理,所以都是從網上現學現用,從如何讀入nrrdnrrdnrrd文件到學長教我如何實現dicmdicmdicm文件數據的有效讀入(這里面涉及到的知識點我忘記了,我還傻乎乎的調用了pythonpythonpython讀dicmdicmdicm文件的庫函數,后來學長指出我的錯誤,索性我就直接用了學長的讀dicmdicmdicm文件的函數),注意是需要歸一化操作的。
2、一開始我基本實現了功能之后我就沒管掛機了,后面我組長(和我一起進行數據預處理工作,她要是有博客的話我就@她了,一個超好看的妹子 ),比對結果圖和用軟件打開的原圖時發現有很大的問題(遇事不要慌,有問題就解決問題 ),切出來的腎癌部分完全對不上,而且紋路也不對,然后我就陷入了無窮的調bugbugbug中,但是始終不知道哪錯了,其實現在回想起來當時應該發現第3條里面的錯誤的,但是并沒有(因為自己懶 ),于是嘗試失敗!
3、之后向學長匯報結果,請教學長時,學長跟我們(我和前面提到的組長妹子)說,圖片橫縱坐標是反的,然后從nrrdnrrdnrrd文件對應的dicmdicmdicm索引不是正向對應的,而是反向的(不是iii到iii的,而是iii到len?1?ilen-1-ilen?1?i的),我幡然醒悟,原來我是這里沒注意啊,趕緊又是滾回去調bugbugbug。
4、經歷過第3點的指點之后,我花了將近一周的時間(其實并沒有,中間有上課的)修bugbugbug,然后對比結果圖和軟件打開的圖,自我感覺應該沒問題了,扔給組長仔細全面對比去了(其實是因為我電腦上的軟件不知道為啥抽風了,不方便比對),然后組長妹子對比完之后告訴我還是不對,腎癌紋路不對,我懵逼,不知道為啥不對的情況下決定先確定一個事情----我沒有切錯幀(因為CT圖是空間上的切片,所以大多數情況下前后幀差別不大),于是我經過不斷地調代碼跑圖扔給組長(其實我也有對比的),最后總算是確定沒有切錯幀。這個時候問題來了,幀沒錯但是腫瘤部分紋路還是不對(我們的預處理是保留腫瘤部分,非腫瘤部分置為黑色背景色),我想了好久都沒有想出來到底為啥。
5、在晚上睡不著的時候腦子里無意閃現出一個方法驗證:因為腫瘤區域太小了不好比對,我們為何不反向操作,把腫瘤部分置為黑色,其他部分保留原色,這樣不是可以同步解決兩個問題:一個是4中的切錯幀的問題,一個是為啥會紋路不對的問題。第二天就試了試我的想法,運行出來的效果圖確實可以解決目前遇到的問題,錯誤一目了然:每個病人的圖效果是反的(我把第一張圖腫瘤的位置放在了最后一張圖上去切,難怪會幀對紋路不對),僅花了半天就修好了我的bugbugbug(腦子果然是個好東西 ),切出來的效果圖也沒出錯了。(真的是難為我的組長了 )
6、目前效果圖存在一點點小瑕疵:切出來的圖感覺帶上了一層蒙蒙的灰一樣,清晰度沒有軟件的高(由于我不是搞計算機圖形學的我不太懂),如果有哪位博主知道為什么以及怎么解決,本人萬分感激,歡迎評論區留言討論。
以下是我pythonpythonpython代碼實現的數據預處理,大部分都有解釋,雖然我已經優化了代碼的復雜度了,但是代碼寫得還是不夠優美,實在抱歉,有困惑的地方歡迎留言:
# 從nrrd原圖圖像中單獨切出腫瘤區域,尋找合適腫瘤圖片尺寸并放置中心位置 # !!!注意請使用絕對路徑,并且路徑不要包含中文 import os; from PIL import Image import numpy as np import matplotlib.pyplot as plt import nrrd import pydicom from scipy import ndimage import cv2 import scipy.misc import time from skimage import exposuredef findAllfile(path, allfile):filelist = os.listdir(path)for filename in filelist:filepath = path + "/" + filename;if os.path.isdir(filepath):# print(filepath)findAllfile(filepath, allfile)else:allfile.append(filepath)return allfile# 尋找腫瘤區域邊界大小并按序返回上(u)下(d)左(l)右(r) # 有效區域像素值為255 def find_boundary(image):# r行,w列rr, w = image.shape;u = w - 1;d = 0;l = rr - 1;r = 0;for i in range(rr):for j in range(w):if image[i][j] == 1:u = min(u, i);d = max(d, i);l = min(l, j);r = max(r, j);return u, d, l, r;# 確定有效裁剪邊界 def decide_boundary(pos, max_length):# r行,w列rr = 512;w = 512;u = pos[0];d = pos[1];l = pos[2];r = pos[3];tmp1 = d - u + 1;tmp2 = (max_length - tmp1) // 2;if u - tmp2 < 0:u = 0;d = max_length - 1;elif d + tmp2 >= rr:u = rr - max_length;d = rr - 1;else:u = u - tmp2;d = u + (max_length - 1);tmp1 = r - l + 1;tmp2 = (max_length - tmp1) // 2;if l - tmp2 < 0:l = 0;r = max_length - 1;elif r + tmp2 >= w:l = w - max_length;r = w - 1;else:l = l - tmp2;r = l + (max_length - 1);return u, d, l, r;def convert_from_dicom_to_png(img, low_window, high_window):# print("shape is ",img.shape);lungwin = np.array([low_window * 1., high_window * 1.]);newimg = (img - lungwin[0]) / (lungwin[1] - lungwin[0]); # 歸一化newimg = (newimg * 255).astype('uint8'); # 將像素值擴展到[0,255]return newimg;"""print(newimg.shape);print(newimg);print(save_path)plt.imshow(newimg, "gray");plt.show();os.system("pause");"""# 將原圖中不是腫瘤部分(背景)設置為黑色 # nrrd1_file:腫瘤數組 # nrrd2_file:腎數組 def set_back(dicm_file, nrrd1_file, nrrd2_file):r, w = dicm_file.shape;for i in range(r):for j in range(w):if nrrd1_file[i][j] == 0: # 未標記部分置為黑色背景dicm_file[i][j] = -2048;return dicm_file;# 讀取dicm文件并歸一化值 def dicom_read(src):ds = pydicom.read_file(src)dicom_i = np.int16(ds.pixel_array)# 轉換為HU單位intercept = ds.RescaleInterceptslope = ds.RescaleSlopeif slope != 1:dicom_i = slope * dicom_i.astype(np.float64)dicom_i.astype(np.int16)dicom_i += np.int16(intercept)return dicom_i# 將單獨切出來的腫瘤區域放在最中間,只保留有效區域,圖像尺寸減小 # 切出一個正方形,保證腫瘤離邊界一定距離 def cut_zhongliu_yuantu_solve(original, image_result):# 從nrrd文件中讀取已標注幀,并保存有效dicm文件boundary_set = [];boundary_set_tmp = [];nrrd1_file_set = [];nrrd1_file_set_tmp = [];nrrd2_file_set = [];nrrd2_file_set_tmp = [];dicm_filepath_set = []; # 存放有效的dicm文件路徑dicm_filepath_tmp = []; # 臨時存放當前文件夾下的所有dicm文件路徑# 找出所有的子目錄filelist = os.listdir(original);# 將有標注的腫瘤存放在tag_pos1中tag_pos1 = [];tag_pos2 = [];# 腫瘤總幀數z1 = -1;z2 = -2;max_length = 0;for filename in filelist:# filepath 原始子目錄路徑 D:/MITK/已標記_batch_ans/腎癌filepath = original + "/" + filename;filelist1 = os.listdir(filepath);for filename1 in filelist1:# filepath1 二級子目錄 D:/MITK/已標記_batch_ans/腎癌/ANJINGSRS00003(已標記)filepath1 = filepath + "/" + filename1;if os.path.isdir(filepath1):image_files1 = findAllfile(filepath1, []);dicm_path = [];data_split1 = filepath1.split("/");image_floder1 = data_split1[-2];# image_floder1 文件所在目錄image_name1 = data_split1[-1];# image_name1 文件名稱image_newfloder1 = image_result + "/" + image_floder1 + "/" + image_name1;# 判斷目錄是否存在,不存在就重建if not os.path.isdir(image_newfloder1):os.makedirs(image_newfloder1);# 處理后的文件路徑image_newpath = image_newfloder1 + "/";# 核心操作t, filepath1_tmp = os.path.split(filepath1);# 獲取腫瘤中已標注的幀tmp = t + "/" + filepath1_tmp;for facepath1 in image_files1:# facepath1 原始文件路徑# 獲取文件名稱if facepath1 == tmp + "/腫瘤.nrrd" or facepath1 == tmp + "/zhongliu.nrrd" or facepath1 == tmp + "/zhongliu(L).nrrd" or facepath1 == tmp + "/zhongliu(R).nrrd":nrrd_data1, nrrd_options1 = nrrd.read(facepath1);x1, y1, z1 = nrrd_data1.shape;'''nrrd_data1_tmp = nrrd_data1.copy();for i in range(z1):for j in range(x1):for k in range(y1):nrrd_data1_tmp[j][k][i] = nrrd_data1[j][k][z1 - 1 - i];print(i);nrrd_data1 = nrrd_data1_tmp;'''nrrd_data1 = nrrd_data1.transpose((1, 0, 2));for i in range(z1):if nrrd_data1[:, :, i].any() != 0:# print(nrrd_data1[:,:,i]);# os.system("pause")tag_pos1.append(z1 - 1 - i);# 對應索引反向取值u, d, l, r = find_boundary(nrrd_data1[:, :, i]);max_length = max(d - u + 1, max_length);max_length = max(r - l + 1, max_length);boundary_set_tmp.append([u, d, l, r]); # 通過nrrd標記文件確定邊界nrrd1_file_set_tmp.append(nrrd_data1[:, :, i]);# tag_pos1 = sorted(tag_pos1);# 獲取腎壁中已標注的幀elif facepath1 == tmp + "/腎壁.nrrd" or facepath1 == tmp + "/shenbi.nrrd" or facepath1 == tmp + "/shenbi(L).nrrd" or facepath1 == tmp + "/shenbi(R).nrrd":nrrd_data2, nrrd_options2 = nrrd.read(facepath1);nrrd_data2 = nrrd_data2.transpose((1, 0, 2));x2, y2, z2 = nrrd_data2.shape;for i in range(z2):if nrrd_data2[:, :, i].any() != 0:tag_pos2.append(z2 - 1 - i);nrrd2_file_set_tmp.append(nrrd_data2[:, :, i]);# tag_pos2 = sorted(tag_pos2);# pass;else:dicm_filepath_tmp.append(facepath1);# 保存所有合格的幀# if z1 == z2 and z1 > 0 and tag_pos1 != [] and tag_pos2 != []:if z1 > 0 and tag_pos1 != []:# print("列表長度:", z1);# print(tag_pos1);# print(tag_pos2);pos_val = 0;dicm_filepath_tmp1 = [];for pos in range(z1):if pos in tag_pos1:# if pos in tag_pos2:dicm_filepath_tmp1.append(dicm_filepath_tmp[pos]);boundary_set.append(boundary_set_tmp[pos_val]);nrrd1_file_set.append(nrrd1_file_set_tmp[pos_val]);nrrd2_file_set.append(nrrd2_file_set_tmp[pos_val]);pos_val += 1;dicm_filepath_tmp1.reverse();for dicm_path in dicm_filepath_tmp1:dicm_filepath_set.append(dicm_path);tag_pos1 = [];tag_pos2 = [];z1 = -1;z2 = -2;# 清空臨時存放的當前文件夾下的所有文件路徑dicm_filepath_tmp = [];dicm_filepath_tmp1 = [];boundary_set_tmp = [];nrrd1_file_set_tmp = [];nrrd2_file_set_tmp = [];# 總的有效dicm文件數量file_length = len(dicm_filepath_set);boundary_set_len = np.array(boundary_set).shape[0];print("file_length is ", file_length);print("boundary_set_len is ", boundary_set_len);max_length += 40;'''# 確定每幀的分割邊界for pos in range(file_length):du, dd, dl, dr = decide_boundary(boundary_set[pos], max_length);# print(du, dd, dl, dr);# os.system("pause");boundary_set[pos][0] = du;boundary_set[pos][1] = dd;boundary_set[pos][2] = dl;boundary_set[pos][3] = dr;'''# 對dicm文件進行分割,切出腫瘤位置for pos in range(file_length):# dataset = pydicom.read_file(dicm_filepath_set[pos]);# dataset_array = dataset.pixel_array;dataset_array = dicom_read(dicm_filepath_set[pos]);# print(dataset_array);# os.system("pause");#dataset_array_new = dataset_array#high = np.max(dataset_array_new);#low = np.min(dataset_array_new);high = 700;low = -700;dataset_array_new = convert_from_dicom_to_png(np.array(dataset_array), low, high);dataset_array_new1 = set_back(dataset_array_new, nrrd1_file_set[pos], nrrd2_file_set[pos]);# dataset_array_new1 = exposure.adjust_gamma(dataset_array_new1, 2);print(dicm_filepath_set[pos]);# plt.imshow(dataset_array);# plt.show();# os.system("pause");'''du = boundary_set[pos][0];dd = boundary_set[pos][1];dl = boundary_set[pos][2];dr = boundary_set[pos][3];'''du, dd, dl, dr = decide_boundary(boundary_set[pos], max_length);new_dicm_image = dataset_array_new1[du:dd, dl:dr];#new_dicm_image = dataset_array_new1;path = dicm_filepath_set[pos].split("/");# 新圖保存路徑image_name = image_result + "/" + path[-3] + "/" + path[-2] + "/small_image_" + str(pos) + ".png";cv2.imwrite(image_name, new_dicm_image);# print(image_name);# plt.imshow(new_dicm_image, "gray");# plt.show();# os.system("pause");if __name__ == '__main__':# 原始dicm文件路徑original = 'D:/MITK/targeted_tmp';# 減小原圖圖片尺寸,保留有效腫瘤區域small_size_image_result = 'D:/MITK/targeted_only_zhong_liu_small_picture_new14';cut_zhongliu_yuantu_solve(original, small_size_image_result);總結
以上是生活随笔為你收集整理的CT影像数据(nrrd文件和dicm文件)的读取和预处理的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: comps电磁场模拟软件_电力系统仿真软
- 下一篇: DB2 SQLCODE 异常大全编辑(二
