Spaces:
Runtime error
Runtime error
| import os | |
| import sys | |
| import numpy as np | |
| import torch | |
| import cv2 | |
| import time | |
| from PIL import Image | |
| import argparse | |
| from openslide import OpenSlide | |
| sys.path.append(os.getcwd()) | |
| from tools.LeNet5_different_inputSizes import select_model | |
| from tools.PredictingTools import LoadData, TestToDataframe, SaveMask, heatmap | |
| from tools.CroppingTools import read_slide_to_level, mask_slide_to_level, OTSU_slide_to_level | |
| from tools.AnalyzingTools import Create_Overlay, mask_to_xml | |
| from tools.ScoringTools import Jaccard_Index, Dice_Coefficient | |
| parser = argparse.ArgumentParser(description='Predicting') | |
| ######################################################################################################## | |
| parser.add_argument('--input_dir', type=str, default=r"./Segmentation/segmentation_results/wsi.txt", help='a txt file containing path of the WSIs such as .svs, .mirx, .tiff, .ndpi files') | |
| parser.add_argument('--out_dir', type=str, default=r"./Segmentation/segmentation_results", help='output directory') | |
| parser.add_argument('--data_source', default='source_name', help='the source that you have got the WSIs', dest='data_source') | |
| parser.add_argument('--voting', type=str, default=None, help='\"hard\", \"soft\" or None') | |
| parser.add_argument('--resolution', type=int, default=4, help='resolution of the prediction, 1 is the cropsize, 2 is half of the cropsize, 3 is quarter of the cropsize etc.') | |
| ######################################################################################################## | |
| FLAGS = parser.parse_args() | |
| mdl_basename = "LeNet5" | |
| level_size:str = "L4_128" | |
| data_source:str = FLAGS.data_source | |
| mask_out_dir = FLAGS.out_dir | |
| device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") | |
| txt_path = FLAGS.input_dir | |
| slidepaths = [] | |
| xmlpaths = [] | |
| slidepaths = [] | |
| with open(txt_path) as f: | |
| for line in f: | |
| slidepath = line.strip() # Remove leading/trailing spaces and newline characters | |
| xmlpath = slidepath.rsplit('.', 1)[0] + '.xml' | |
| xmlpaths.append(xmlpath) | |
| slidepaths.append(slidepath) | |
| pred_resolution = FLAGS.resolution #it is for changing the size of stride, bigger number means smaller stride. | |
| # 1 is the cropsize, 2 is half of the cropsize, 3 is quarter of the cropsize etc. | |
| voting = FLAGS.voting | |
| model_dir = os.path.join(mask_out_dir, mdl_basename) | |
| mask_out_dir = os.path.join(model_dir, f"resolution_{pred_resolution}") | |
| mask_out_dir = os.path.join(mask_out_dir, data_source) | |
| os.makedirs(mask_out_dir, exist_ok=True) | |
| scores_dir = os.path.join(mask_out_dir, 'scores.txt') | |
| with open(scores_dir, 'w') as fil: | |
| fil.write("slide_name, jaccard_score, dice_coef\n") | |
| otsu_scores_dir = os.path.join(mask_out_dir, 'OTSU_scores.txt') | |
| with open(scores_dir, 'w') as fil: | |
| fil.write("slide_name, jaccard_score, dice_coef\n") | |
| # './results/{FLAGS.data_source}/{FLAGS.Level_patch}/trained_models/{FLAGS.model_type}.pth' | |
| model_level, model_cropsize = level_size[1:].split("_") | |
| model_level, model_cropsize = int(model_level), int(model_cropsize) | |
| model_path = r"Segmentation\model\LeNet5Segmentation.pth" | |
| means = np.load(r"Segmentation\model\means.npy") | |
| stds = np.load(r"Segmentation\model\stds.npy") | |
| stride = int(model_cropsize//2**(pred_resolution-1)) | |
| wanted_rlength = 2**(model_level-2) #we do -2 because our model base mpp is 0.25 | |
| #print("wanted_rlength: ", wanted_rlength) | |
| model = select_model(model_cropsize) | |
| model.to(device) | |
| model.load_state_dict(torch.load(model_path, map_location=device)) | |
| with open(scores_dir, 'a') as scores_file: | |
| with open(otsu_scores_dir, 'a') as otsu_scores_file: | |
| for slide_path, xml_path in zip(slidepaths, xmlpaths): | |
| start_time = time.time() | |
| slide_name = os.path.basename(slide_path).split('.')[0] | |
| print(slide_name) | |
| save_dir = os.path.join(mask_out_dir, slide_name) | |
| os.makedirs(save_dir, exist_ok=True) | |
| predicted_mask_path = os.path.join(save_dir,'mask.png') | |
| slide = OpenSlide(slide_path) | |
| try: | |
| current_res = float(slide.properties.get('openslide.mpp-x')) | |
| except: | |
| try: | |
| res_type = slide.properties.get("tiff.ResolutionUnit") | |
| if res_type == "centimeter": | |
| numerator = 10000 | |
| elif res_type == "inch": | |
| numerator = 25400 | |
| current_res = numerator / float(slide.properties.get("tiff.XResolution")) | |
| except: | |
| raise Exception('Unknown Val_x') | |
| if current_res < 0.3: # resolution:0.25um/pixel | |
| current_res = 0.25 | |
| elif current_res < 0.6: # resolution:0.5um/pixel | |
| current_res = 0.5 | |
| xml_downscale = wanted_rlength / current_res | |
| img, downscale = read_slide_to_level(slide, rlenght=wanted_rlength) | |
| img_height, img_width = img.height, img.width | |
| img.save(os.path.join(save_dir,'original.png')) | |
| img = np.array(img) | |
| dataloader = LoadData(img_arr=img, cropsize=model_cropsize, stride=stride, means=means, stds=stds) | |
| pred_df = TestToDataframe(model, device, dataloader) | |
| pred_df.to_csv(os.path.join(save_dir,'preds.csv'), index=False) | |
| SaveMask(pred_df, img_height, img_width, model_cropsize, predicted_mask_path, voting=voting, class_weights=(0.75, 0.25)) | |
| inverted_mask_im = cv2.imread(predicted_mask_path, cv2.IMREAD_GRAYSCALE) | |
| mask_im = cv2.bitwise_not(inverted_mask_im) | |
| mask_to_xml(mask_im, os.path.join(save_dir, slide_name + '.xml'), downscale_factor=downscale) | |
| end_time = time.time() | |
| time_taken = end_time - start_time | |
| print(f"Time taken for {slide_name}: {time_taken} seconds") | |
| slide.close() | |
| print("done with: " + slide_name) | |
| print("-----------------------------------------------------------") | |