def compute_edge_integral(im_rgb, th_Canny_1=130, th_Canny_2=230): im_tissue_gray = cv2.cvtColor(im_rgb, cv2.COLOR_RGB2GRAY) im_edge_255 = cv2.Canny(im_tissue_gray, th_Canny_1, th_Canny_2) _, im_edge_bin = cv2.threshold(im_edge_255, 1, 1, cv2.THRESH_BINARY) im_uint64_edge_integral = integral_image(im_edge_bin) return im_uint64_edge_integral, im_edge_bin
def compute_integral_image_of_mask(fn_slide, dir_mask, level, postfix_ext_mask): im_01_mask_l, w_m_l, h_m_l = load_mask() if 1 != im_01_mask_l.max(): print('Something wrong !! : 1 != im_01_mask_l.max()') # integral image를 구한다. im_uint64_int_mask = integral_image(im_01_mask_l) # blob의 area를 구한다. #area_blob = integrate(im_int, (0, 0), (h - 1, w - 1)) return im_uint64_int_mask
def h_and_s_otsu_01_integral(im_rgb, scale_otsu): im_01_h_and_s = h_and_s_otsu_01(im_rgb, scale_otsu) ''' im_0255_h_and_s = 255 * im_01_h_and_s cv2.imshow('im_0255_h_and_e', im_0255_h_and_s.astype(np.uint8)) cv2.waitKey() ''' im_uint64_int_h_and_s = integral_image(im_01_h_and_s) return im_uint64_int_h_and_s, im_01_h_and_s
def getHaarValueSimple(img, haar): numRect = len(haar) # 2 value = 0 imgInt = [] for imgs in img: imgInt.append(integral.integral_image(imgs)) c = -1 for i in range(0,numRect): c *= -1 value += imgSubAreaSimple(imgInt,haar[i][0],haar[i][1])*c return abs(value)
def hessian(img): scales = [] s = 2 k = math.pow(2,0.25) for i in range(12): image = hessian_matrix_det(img, sigma=1.2*i) # image = hessian_matrix_det(img, sigma=math.pow(k,i)*s) Hrr, Hrc, Hcc = hessian_matrix(integral_image(img), sigma=math.pow(k,i)*s, order='rc') det = Hrr*Hcc - np.power((0.9*Hrc),2) scales.append(image) keypts = keypt(scales) return keypts
def bradley_roth(self, verbose=False): if verbose: info = {} arr = np.array(self.image).astype('int64') intImg = integral_image(arr) s = np.round(arr.shape[1] / 8) t = 15 out = np.zeros(arr.shape) for i in range(0, arr.shape[1]): for j in range(0, arr.shape[0]): x1 = int(i - s / 2) x2 = int(i + s / 2) y1 = int(j - s / 2) y2 = int(j + s / 2) #bound validation if x2 >= arr.shape[1]: x2 = arr.shape[1] - 1 if y2 >= arr.shape[0]: y2 = arr.shape[0] - 1 #count = (x2 - x1) * (y2 - y1) x1 -= 1 y1 -= 1 if (x1 < 0): x1 = 0 if (y1 < 0): y1 = 0 count = (x2 - x1) * (y2 - y1) tot = intImg[y2, x2] - intImg[y2, x1] - intImg[y1, x2] + intImg[y1, x1] if (arr[j, i] * count) <= (tot * (100 - t) / 100): out[j, i] = 0 else: out[j, i] = 1 toImg = copy.copy(out) toImg[toImg == 1] = 255 self.binary_image = out self.image = Image.fromarray(toImg) if verbose: info["integral_image"] = intImg.tolist() img = self.image.convert("L") img.save("./static/cache/" + self.prefix + "binary.jpg") info["link"] = "./static/cache/" + self.prefix + "binary.jpg" return info
def processDataset(): # Create memmap array: shape_arr = calcArrayShape() dataset_array = np.memmap(TEMP_FILE, dtype=np.float32, mode='w+', shape=shape_arr) print('Created temporary array: %s of size %s' % (TEMP_FILE, str(shape_arr))) for offset_index, cur_dir in enumerate(DATASET_DIRECTORIES): print('Current directory: ' + cur_dir) input_file_list = [ cur_dir + f for f in listdir(cur_dir) if f.split('.')[-1] == 'bmp' ] input_file_list.sort() # Calculate offset of array if offset_index == 0: offset = 0 else: offset += DATASET_LENGTHS[offset_index - 1] # Read patches and store into array for cur_patch_num in range(DATASET_LENGTHS[offset_index]): cur_patch = getPatch(input_file_list, *patchPositionByIndex(cur_patch_num)) cur_patch_gradients = Utils.getHoG(cur_patch) for i in range(DIRECTIONS_NUM + 2): if i == 0: dataset_array[cur_patch_num + offset, :, :, i] = cur_patch else: dataset_array[cur_patch_num + offset, :, :, i] = intg.integral_image( cur_patch_gradients[:, :, i - 1]) sys.stdout.write('\r' + 'Calculating %i of %i patches' % (cur_patch_num, DATASET_LENGTHS[offset_index])) sys.stdout.write('\r' + 'Total of %i patches calculated\n' % DATASET_LENGTHS[offset_index]) print('Calculated temp array') np.save(OUTPUT_FILE_NAME, dataset_array) print('Saved to %s' % OUTPUT_FILE_NAME) del dataset_array os.remove(TEMP_FILE) print('Delete temporary array: %s' % TEMP_FILE)
def getHarrError(dataList, coordList, threshold, labels, weights): fValues = [] fClass = [] err = [] imgInt = [] for imgs in dataList: imgInt.append(integral.integral_image(imgs)) for t in range(0,len(coordList)): # Change of coordList to list of tensors: (numHaars,Point,Coordinate) auxList = [] auxCoord = coordList[t].copy() for r in range(0,len(auxCoord[0])): tmp = np.zeros([len(auxCoord),len(auxCoord[0]),2]) for n in range(0,len(auxCoord)): tmp[n,0,:] = np.asarray(auxCoord[n][r][0]) tmp[n,1,:] = np.asarray(auxCoord[n][r][1]) auxList.append(tmp) haarValue = getHaarValue(imgInt,auxList) labelsMat = np.tile(labels,(len(auxCoord),1)).T classValue = ((haarValue>threshold)!=labelsMat)*1 # 1: wrong class, 0: correct class fValues.append(haarValue) fClass.append(classValue) err.append(np.sum(classValue.T*weights,axis=1)) return err,fValues,fClass
def get_surf_vector(image): #Preprocess Image feature = [] image = cv2.resize(image, DIM, interpolation = cv2.INTER_AREA) gray_temp = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY).astype('float') image = cv2.normalize(gray_temp, None, 0, 1, cv2.NORM_MINMAX) #Get Interal/Summation Representation image = integral_image(image) for scale in scale_values: #Get Hessian Determinant and Get Local Maximums det = hessian_matrix_det(image, scale) blobs = peak_local_max(det) #We Need to Add the Scale Information to the feature for blob in blobs: x_coordinate = blob[0] y_coordinate = blob[1] point = [float(x_coordinate), float(y_coordinate), scale] feature.append(point) return feature
def patch_sampling(slide, mask, nonzerox, nonzeroy, **opts): """Patch sampling on whole slide image by random points over an uniform distribution. TO-DO +++++ Optimize: compute non zero list in the caller and pass only the intersting part -- will help in batch linear sampling... Arguments +++++++++ :param obj slide: OpenSlide Object :param obj mask: mask image as (0, 1) int Numpy array :param list nonzerox, nonzeroy: Numpy arrays of nonzero points over `mask` Keyword arguments +++++++++++++++++ :param int start_idx: start index on the mask's nonzero point list. Ignored if `mode` == 'random' :param obj logger: a pymod:logging instance :param int slide_level: level of mask :param int patch_size: size of patch scala integer n :param int n_samples: the number of patches to extract (batch size) ...plaese complete me! :return list: patches (RGB images), list of patch points (starting from left top), last used nonzero mask point's index or None (random sampling only) """ global logger # def values updated from **opts dopts = { 'area_overlap' : .6, 'bad_batch_size' : 500, 'gray_threshold' : 90, 'margin_width_x' : 250, # as per original code, watch out! 'margin_width_y' : 50, # ditto 'method' : 'random', 'n_samples' : 100, 'patch_size' : 224, 'slide_level' : 5, 'start_idx' : 0, 'white_level' : 200, 'white_threshold' : .3, 'white_threshold_incr' : .05, 'white_threshold_max' : .7, } for dk in dopts: # [BUG] if called with a missing key, won't get the default!? try: dopts[dk] = opts.pop(dk, None) except KeyError as k: pass # reinject as standard var... This is just because I'm lazy and want # to keep the original names ;-) exec "{} = dopts[dk]".format(dk) if opts: # leftovers... raise RuntimeError, 'Unexpected options {}'.format(opts) logger.debug("kw opts:\n{}.".format(dopts)) # bind to aux functions bfn = { 'get_index' : None, 'get_white_threshold' : None, 'is_batch_over' : None, } for n in bfn.keys(): bfn[n] = globals()['{}__{}'.format(n, method)] if not callable(bfn[n]): raise RuntimeError, '[BUG] {} => {}: invalid aux function binding'.format(n, bfn[n]) report = { 'out_of_boundary' : 0, 'on_border' : 0, 'black_patches' : 0, 'white_patches' : 0, 'gray_patches' : 0, } patch_list = [] patch_point = [] # patch size at given level or resolution level_patch_size = int(patch_size / slide.level_downsamples[slide_level]) x_l, y_l = nonzerox, nonzeroy x_ln, y_ln = len(x_l), len(y_l) logger.info('Working mask has {} x {} nonzero points'.format(x_ln, len(y_l))) if x_ln < level_patch_size * 2: logger.info( "Not enough nonzero mask points for at least 2 patches ({} < {})".format( x_ln, level_patch_size ) ) return [], [], None # computing the actual level of resolution (dot product) x_ws = (np.round(x_l * slide.level_downsamples[slide_level])).astype(int) y_ws = (np.round(y_l * slide.level_downsamples[slide_level])).astype(int) cnt = 0 # good patch counter nt_cnt = 0 # not taken patch counter p_iterator = bfn['get_index'](start_idx, x_ln - 1) p_idx = start_idx # just for init purposes # while(not bfn['is_batch_over'](cnt, n_samples)): while(cnt < n_samples): # pick an index... try: p_idx = p_iterator.next() except StopIteration: break # ...corresponding point in the mask level_point_x, level_point_y = x_l[p_idx], y_l[p_idx] # [BUG] otsu threshold takes also border, so discard?? mmh, needs # double check (risk missing stuff...) if is_point_on_border(level_point_x, level_point_y, margin_width_x, margin_width_y): # logger.debug( # 'Skipping point on mask border: {}x ?< {}, {}y ?< {}'.format( # level_point_x, margin_width_x, level_point_y, margin_width_y # ) # ) report['on_border'] += 1 continue if not is_point_within_boundaries( level_point_x, level_point_y, level_patch_size, mask.shape ): # logger.debug( # 'Skipping point out of mask boundary: {} ?> {}, {} ?> {}'.format( # level_point_x, mask.shape[0], level_point_y, mask.shape[1] # ) # ) report['out_of_boundary'] += 1 continue # make patch from mask image level_patch_mask = mask[ int(level_point_x) : int(level_point_x + level_patch_size), int(level_point_y) : int(level_point_y + level_patch_size) ] # apply integral ii_map = integral_image(level_patch_mask) ii_sum = integrate(ii_map, (0, 0), (level_patch_size - 1, level_patch_size - 1)) # total patch area should covers at least x% of the annotation # region overlap = float(ii_sum) / (level_patch_size**2) if overlap < area_overlap: continue # square patch (RGB point array in [0, 255]) patch = slide.read_region( (y_ws[p_idx], x_ws[p_idx]), 0, (patch_size, patch_size) ) patch = np.array(patch) if np.sum(patch) == 0: report['black_patches'] += 1 # logger.debug('Skipping black patch at {}, {}'.format(level_point_x, level_point_y)) continue # check almost white RGB values. white_mask = patch[:,:,0:3] > white_level # sum over the 3 RGB channels if float(np.sum(white_mask)) / (patch_size**2*3) <= white_threshold: patch = cv2.cvtColor(patch, cv2.COLOR_RGBA2BGR) if np.mean(patch) > gray_threshold: # got a good one... patch_list.append(patch) # ...with its location patch_point.append((x_l[p_idx], y_l[p_idx])) cnt += 1 else: report['gray_patches'] += 1 # logger.debug('Skipping grey patch at {}, {}'.format(x_l[p_idx], y_l[p_idx])) else: # bad one: too white report['white_patches'] += 1 nt_cnt += 1 # possibly get an update nt_cnt, white_threshold = bfn['get_white_threshold']( nt_cnt, bad_batch_size, white_threshold, white_threshold_max, white_threshold_incr ) if white_threshold == None: logger.warning('Max white threshold reached! Bailing out') break # {end while} logger.info( 'Skipped points: {} on mask boder, {} out of mask boundary'.format( report['on_border'], report['out_of_boundary'] ) ) logger.info( 'Skipped patches: {} black, {} white, {} gray'.format( report['black_patches'], report['white_patches'], report['gray_patches'] ) ) logger.info('Extracted {} patches'.format(len(patch_point))) # in 'random' method, only one batch is done, so it doens't make sense to # return the last index. Instead signal that we're over with sampling. p_idx = None if method == 'random' else p_idx return patch_list, patch_point, p_idx
def patch_sampling_using_integral(slide,slide_level,mask,patch_size,patch_num): """ patch sampling on whole slide image input: slide = OpenSlide Object slide_level = level of mask mask = mask image ( 0-1 int type nd-array) patch_size = size of patch scala integer n patch_num = the number of output patches output: list of patches(RGB Image), list of patch point (starting from left top) """ patch_list = [] # patches patch_point = [] # patch locations # taking the nonzero points in the mask x_l,y_l = mask.nonzero() #slide_level=7 if len(x_l) > patch_size/slide.level_downsamples[slide_level]*2: level_patch_size = int(patch_size/slide.level_downsamples[slide_level]) print 'DEBUGGG: ', slide_level # computing the actual level of resolution # applying the nonzero mask as a dot product x_ws = (np.round(x_l*slide.level_downsamples[slide_level])).astype(int) y_ws = (np.round(y_l*slide.level_downsamples[slide_level])).astype(int) cnt = 0 # patch counter nt_cnt = 1 # not taken counter white_threshold = .3 #white_threshold = 1.0 while(cnt < patch_num) : # sampling from random distribution p_idx = randint(0,len(x_l)-1) # picking the random point in the mask level_point_x,level_point_y = x_l[p_idx], y_l[p_idx] if (level_point_y < 50) or (level_point_x < 250): ##new add to check continue # check the boundary to make patch check_bound = np.resize(np.array([level_point_x+level_patch_size,level_point_y+level_patch_size]),(2,)) if check_bound[0] > mask.shape[0] or check_bound[1] > mask.shape[1]: continue # make patch from mask image level_patch_mask = mask[int(level_point_x):int(level_point_x+level_patch_size),int(level_point_y):int(level_point_y+level_patch_size)] # apply integral ii_map = integral_image(level_patch_mask) ii_sum = integrate(ii_map,(0,0),(level_patch_size-1,level_patch_size-1)) area_percent = float(ii_sum)/(level_patch_size**2) # checking if the total area of the patch covers at least 80% of # the annotation region if area_percent<0.6: continue if cnt > patch_num*10+1000: print "There is no more patches to extract in this slide" print "mask region is too small" print "final number of patches : ",len(patch_list) break patch=slide.read_region((y_ws[p_idx],x_ws[p_idx]),0,(patch_size,patch_size)) patch = np.array(patch) #print '[integral] np.sum(patch): ', np.sum(patch) if np.sum(patch)==0: print('[integral] AaAaAH its zeroo!!') continue white_mask = patch[:,:,0:3] > 200 if float(np.sum(white_mask))/(patch_size**2*3) <= white_threshold : #if True: if np.sum(patch)>0: # adding the patch to the patches list patch_list.append(cv2.cvtColor(patch,cv2.COLOR_RGBA2BGR)) # adding the patch location to the list patch_point.append((x_l[p_idx],y_l[p_idx])) cnt += 1 # increasing patch counter else: print 'This is a black patch!' else: nt_cnt += 1 #print 'white_mask sum: ', np.sum(white_mask) #print 'white ratio: ', float(np.sum(white_mask))/(patch_size**2*3) #print 'Rejected location: {0},{1}'.format(x_l[p_idx],y_l[p_idx]) if nt_cnt %1000 == 0: if white_threshold < .7: white_threshold += .05 nt_cnt = 1 print 'Increasing white_threshold of 0.05: ', white_threshold else: print 'No more patches to extract that have more than 30 percent of not white content' break def_pl=[] def_pp=[] for i in range(len(patch_list)): if (np.sum(patch_list[i])>0) and (np.mean(patch_list[i])>90): def_pl.append(patch_list[i]) def_pp.append(patch_point[i]) return def_pl, def_pp
def h_or_e_otsu_01_integral(im_rgb, scale_otsu): im_01_h_or_e = h_or_e_otsu_01(im_rgb, scale_otsu) im_uint64_int_h_or_e = integral_image(im_01_h_or_e) return im_uint64_int_h_or_e, im_01_h_or_e
def h_or_s_otsu_01_integral(im_rgb, scale_otsu): im_01_h_or_s = h_or_s_otsu_01(im_rgb, scale_otsu) im_uint64_int_h_or_s = integral_image(im_01_h_or_s) return im_uint64_int_h_or_s, im_01_h_or_s
def poly2rect(poly): '''Approximates a polygon with an axis-aligned rectangle by minimising the mean of point-to-polygon distances of all points on the rectangle. Parameters ---------- poly : numpy.array a list of 2D points forming a single polygon Returns ------- rect : geomt.rect a 2D rectangle with integer coordinates ''' if len(poly.shape) != 2 or poly.shape[1] != 2: raise ValueError( "Only accepting a numpy array of shape (:,2) as a polygon. Receiving shape {}" .format(poly.shape)) # preparation poly = poly.astype(_np.int32) # make the coordinates integer N = poly.shape[0] tl = poly.min(axis=0) br = poly.max(axis=0) # special cases if N == 0: return rect() if N <= 2 or tl[0] >= br[0] or tl[1] >= br[1]: return rect(min_x=tl[0], min_y=tl[1], max_x=br[0], max_y=br[1]) # convexify if necessary if N > 3: poly = poly[_ss.ConvexHull(poly).vertices] N = poly.shape[0] tl = poly.min(axis=0) br = poly.max(axis=0) # draw polygon perimeter w, h = (br - tl) + 1 poly -= tl # to make poly non-negative coordinates buf = _np.ones((h, w), dtype=_np.uint8) rr, cc = _sd.polygon_perimeter(poly[:, 1], poly[:, 0], shape=buf.shape, clip=True) buf[rr, cc] = 0 # compute distance transform edt = _sn.distance_transform_edt(buf) # compute the integral image img = _sti.integral_image(edt) # optimise r0 = rect(min_x=0, min_y=0, max_x=w - 1, max_y=h - 1) loss0 = rect_perimeter(img, r0) dirty = True while dirty: dirty = False # top if r0.min_y + 1 < r0.max_y: r = rect(min_x=r0.min_x, min_y=r0.min_y + 1, max_x=r0.max_x, max_y=r0.max_y) loss = rect_perimeter(img, r) if loss < loss0: r0 = r loss0 = loss dirty = True # left if r0.min_x + 1 < r0.max_x: r = rect(min_x=r0.min_x + 1, min_y=r0.min_y, max_x=r0.max_x, max_y=r0.max_y) loss = rect_perimeter(img, r) if loss < loss0: r0 = r loss0 = loss dirty = True # bottom if r0.min_y + 1 < r0.max_y: r = rect(min_x=r0.min_x, min_y=r0.min_y, max_x=r0.max_x, max_y=r0.max_y - 1) loss = rect_perimeter(img, r) if loss < loss0: r0 = r loss0 = loss dirty = True # right if r0.min_x + 1 < r0.max_x: r = rect(min_x=r0.min_x, min_y=r0.min_y, max_x=r0.max_x - 1, max_y=r0.max_y) loss = rect_perimeter(img, r) if loss < loss0: r0 = r loss0 = loss dirty = True return rect(min_x=r0.min_x + tl[0], min_y=r0.min_y + tl[1], max_x=r0.max_x + tl[0], max_y=r0.max_y + tl[1])
def int_img(image): return integral_image(image)
def make_rect_mask_from_contour_mask_above(im_01, th, size_tile, interval=1): im_uint64_int = integral_image(im_01) return make_rect_mask_from_mask_integral_above(im_uint64_int, th, size_tile, interval)
def create_other_txt_sequence(file_path_tif,file_path_tis_mask,file_path_mask,list,\ file_path_txt,kind,patch_size,mask_downsample,stride): txt = open(file_path_txt, 'a+') for file in os.listdir(file_path_tif): if "TCGA-2Y-A9H1" in file: continue file_name = file[:-4] lab_mask_name = file_path_mask + file_name + '_mask_' + str( mask_downsample) + '.png' if (file_name in list) and (os.path.exists(lab_mask_name)): tissue_mask_name = file_path_tis_mask + file_name + '_tissue_mask_' + str( mask_downsample) + '.png' tissue_mask = cv2.imread(tissue_mask_name, 0) integral_image_tissue = integral_image(tissue_mask.T / 255) # Make integral image of slide lab_mask = cv2.imread(lab_mask_name, 0) integral_image_lab = integral_image(lab_mask.T / 255) size_patch_lv_k = int(patch_size / mask_downsample) # patch在第mask_level层上映射的大小 print(size_patch_lv_k) slide = OpenSlide(file_path_tif + file) slide_w_lv_0, slide_h_lv_0 = slide.dimensions slide_w = int(slide_w_lv_0 / mask_downsample) slide_h = int(slide_h_lv_0 / mask_downsample) _, contours_lab, _ = cv2.findContours(lab_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) _, contours_tissue, _ = cv2.findContours(tissue_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) p_left = [] p_right = [] p_bottom = [] p_top = [] # Extract random patches on tissue region for contour in contours_tissue: coordinates = (np.squeeze(contour)).T coords_x = coordinates[0] coords_y = coordinates[1] # Bounding box vertex p_left.append(np.min(coords_x)) p_right.append(np.max(coords_x)) p_top.append(np.min(coords_y)) p_bottom.append(np.max(coords_y)) p_x_left = min(p_left) p_x_right = max(p_right) p_y_top = min(p_top) p_y_bottom = max(p_bottom) stride_lv = int(stride / mask_downsample) print(p_x_left, p_x_right, p_y_top, p_y_bottom) for x in range(p_x_left, p_x_right, stride_lv): for y in range(p_y_top, p_y_bottom, stride_lv): if (x + size_patch_lv_k - 1 >= slide_w) or (y + size_patch_lv_k - 1 >= slide_h): continue tissue_integral = integrate(integral_image_tissue, \ (x, y), \ (x + size_patch_lv_k - 1, y + size_patch_lv_k - 1) ) tissue_ratio = tissue_integral / (size_patch_lv_k**2) lab_integral = integrate(integral_image_lab, \ (x, y), \ (x + size_patch_lv_k - 1, y + size_patch_lv_k - 1) ) lab_ratio = lab_integral / (size_patch_lv_k**2) if tissue_ratio > 0.8 and lab_ratio < 0.2: x_lv = int(x + size_patch_lv_k / 2) y_lv = int(y + size_patch_lv_k / 2) patch_x_lv_0 = str((round(x_lv * mask_downsample))) patch_y_lv_0 = str((round(y_lv * mask_downsample))) txt.writelines([ file_name, ',', patch_x_lv_0, ',', patch_y_lv_0, ',', kind, '\n' ]) txt.close()
def tumor_patch_sampling_using_centerwin(slide,slide_level,mask,patch_size,patch_num): """ tumor patch sampling using center window plz input the only tumor mask it will malfunctioned if you input normal mask or tissue mask input parameters are same as patch_sampling_using_integral """ patch_list = [] patch_point = [] window_size = int(32/ slide.level_downsamples[slide_level]) x_l,y_l = mask.nonzero() if len(x_l) > patch_size*2: level_patch_size = int(patch_size/slide.level_downsamples[slide_level]) x_ws = (np.round(x_l*slide.level_downsamples[slide_level])).astype(int) y_ws = (np.round(y_l*slide.level_downsamples[slide_level])).astype(int) cnt=0 while(len(patch_list) < patch_num) : # loop cnt cnt+=1 #random Pick point in mask p_idx = randint(0,len(x_l)-1) #Get the point in mask level_point_x,level_point_y = x_l[p_idx], y_l[p_idx] #Check boundary to make patch check_bound = np.resize(np.array([level_point_x+level_patch_size,level_point_y+level_patch_size]),(2,)) if check_bound[0] > mask.shape[0] or check_bound[1] > mask.shape[1]: continue #make patch from mask image level_patch_mask = mask[int(level_point_x):int(level_point_x+level_patch_size),int(level_point_y):int(level_point_y+level_patch_size)] '''Biggest difference is here''' #apply center window (32x32) cntr_x= (level_patch_size/2)-1 cntr_y= (level_patch_size/2)-1 win_x = cntr_x-window_size/2 win_y = cntr_y-window_size/2 t_window = level_patch_mask[win_x:(win_x+window_size),win_y:(win_y+window_size)] #print level_patch_mask.shape #print win_x #print win_y #apply integral to window ii_map = integral_image(t_window) #print t_window.shape ii_sum = integrate(ii_map,(0,0),(window_size-1,window_size-1)) area_percent = float(ii_sum)/(window_size**2) # print "integral_area: ",area_percent # print "loop count: ",cnt if area_percent <1.0: continue if cnt > patch_num*10+1000: print "There is no moare patches to extract in this slide" print "mask region is too small" print "final number of patches : ",len(patch_list) break #patch,point is appended the list #print "region percent: ",area_percent patch_point.append((x_l[p_idx],y_l[p_idx])) patch=slide.read_region((y_ws[p_idx],x_ws[p_idx]),0,(patch_size,patch_size)) patch =np.array(patch) patch_list.append(cv2.cvtColor(patch,cv2.COLOR_RGBA2BGR)) return patch_list, patch_point
def extract_patch_on_slide( file_path_tif, \ file_path_tis_mask, \ file_path_jpg, \ save_location_path_patch_position_visualize, \ save_location_path_patch_position_csv, \ size_patch): """ -- Intput : file_path_tif : full path file_path_tis_mask : full path file_path_jpg : full path save_location_path_patch_position_visualize : full path save_location_path_patch_position_csv : full path -- Result : Draw patch position. Save coordinate of patch at level_0. """ patch_level = 0 contours_level = 4 mask_level = 4 slide = OpenSlide(file_path_tif) slide_w_lv_4, slide_h_lv_4 = slide.level_dimensions[4] downsample = slide.level_downsamples[4] size_patch_lv_4 = int(size_patch / downsample) # Make integral image of slide tissue_mask = cv2.imread(file_path_tis_mask, 0) integral_image_tissue = integral_image(tissue_mask.T / 255) # Load original bgr_jpg_lv_4 for visualizing patch position wsi_bgr_jpg = cv2.imread(file_path_jpg) wsi_jpg_visualizing_patch_position = wsi_bgr_jpg.copy() print('==> making contours of tissue region from jpg ..') # Find and Draw contours_tissue - (color : blue) _, contours_tissue, _ = cv2.findContours( \ tissue_mask, \ cv2.RETR_TREE, \ cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(wsi_jpg_visualizing_patch_position, \ contours_tissue, -1, (255, 0, 0), 2) # Make csv_writer csv_file = open(save_location_path_patch_position_csv, 'w') fieldnames = ['X', 'Y'] csv_writer = csv.DictWriter(csv_file, fieldnames=fieldnames) csv_writer.writeheader() print('==> Extracting patches randomly on tissue region...') patch_cnt = 0 ### Extract random patches on tissue region for contour in contours_tissue: # Check if contour area is samller than patch area area = cv2.contourArea(contour) area_patch_lv_4 = size_patch_lv_4**2 if area < area_patch_lv_4: continue # Determine number of patches to extract number_patches = int(round(area / area_patch_lv_4 * 1.5)) number_patches = min(50, number_patches) print('contour area : ', area, ' num_patch : ', number_patches) # Get coordinates of contour (level : 4) coordinates = (np.squeeze(contour)).T coords_x = coordinates[0] coords_y = coordinates[1] # Bounding box vertex p_x_left = np.min(coords_x) p_x_right = np.max(coords_x) p_y_top = np.min(coords_y) p_y_bottom = np.max(coords_y) # Make candidates of patch coordinate (level : 4) candidate_x = \ np.arange(round(p_x_left), round(p_x_right)).astype(int) candidate_y = \ np.arange(round(p_y_top), round(p_y_bottom)).astype(int) # Pick coordinates randomly len_x = candidate_x.shape[0] len_y = candidate_y.shape[0] number_patches = min(number_patches, len_x) number_patches = min(number_patches, len_y) random_index_x = np.random.choice(len_x, number_patches, replace=False) random_index_y = np.random.choice(len_y, number_patches, replace=True) for i in range(number_patches): patch_x = candidate_x[random_index_x[i]] patch_y = candidate_y[random_index_y[i]] # Check if out of range if (patch_x + size_patch_lv_4 > slide_w_lv_4) or \ (patch_y + size_patch_lv_4 > slide_h_lv_4): continue # Check ratio of tumor region tissue_integral = integrate(integral_image_tissue, \ (patch_x, patch_y), \ (patch_x + size_patch_lv_4 - 1, patch_y + size_patch_lv_4 - 1)) tissue_ratio = tissue_integral / (size_patch_lv_4**2) if tissue_ratio < 0.9: continue # Save patches position to csv file. patch_x_lv_0 = int(round(patch_x * downsample)) patch_y_lv_0 = int(round(patch_y * downsample)) csv_writer.writerow({'X': patch_x_lv_0, 'Y': patch_y_lv_0}) patch_cnt += 1 # save cut patches im = slide.read_region((patch_x_lv_0, patch_y_lv_0), 0, (size_patch, size_patch)) im_rgba = np.array(im) im_rgb = cv2.cvtColor(im_rgba, cv2.COLOR_RGBA2RGB) cur_patient_name = file_path_tif.split('/')[4] cur_patient_name = cur_patient_name.split('.')[0] global ID cur_cut_name = save_cut_path_positive_patch_17 + cur_patient_name + '_' + str( ID) + '.jpg' ID += 1 print('cur_cut_name', cur_cut_name) cv2.imwrite(cur_cut_name, im_rgb) # Draw patch position (color : Green) cv2.rectangle(wsi_jpg_visualizing_patch_position, \ (patch_x, patch_y), \ (patch_x + size_patch_lv_4, patch_y + size_patch_lv_4), \ (0, 255, 0), \ thickness=1) print('slide :\t', file_path_tif) print('patch_cnt:\t', patch_cnt) # Save visualizing image. cv2.imwrite(save_location_path_patch_position_visualize, \ wsi_jpg_visualizing_patch_position) csv_file.close()
def patch_sampling_using_integral(slide,slide_level,mask,patch_size,patch_num): """ patch sampling on whole slide image slide = OpenSlide Object slide_level = level of mask mask = mask image ( 0-1 int type nd-array) patch_size = size of patch scala integer n patch_num = the number of output patches return list of patches(RGB Image), list of patch point(left top) """ patch_list = [] patch_point = [] x_l,y_l = mask.nonzero() if len(x_l) > patch_size*2: level_patch_size = int(patch_size/slide.level_downsamples[slide_level]) x_ws = (np.round(x_l*slide.level_downsamples[slide_level])).astype(int) y_ws = (np.round(y_l*slide.level_downsamples[slide_level])).astype(int) cnt=0 while(len(patch_list) < patch_num) : # loop cnt cnt+=1 #random Pick point in mask p_idx = randint(0,len(x_l)-1) #Get the point in mask level_point_x,level_point_y = x_l[p_idx], y_l[p_idx] #Check boundary to make patch check_bound = np.resize(np.array([level_point_x+level_patch_size,level_point_y+level_patch_size]),(2,)) if check_bound[0] > mask.shape[0] or check_bound[1] > mask.shape[1]: continue #make patch from mask image level_patch_mask = mask[int(level_point_x):int(level_point_x+level_patch_size),int(level_point_y):int(level_point_y+level_patch_size)] #apply integral ii_map = integral_image(level_patch_mask) ii_sum = integrate(ii_map,(0,0),(level_patch_size-1,level_patch_size-1)) area_percent = float(ii_sum)/(level_patch_size**2) # print "integral_area: ",area_percent # print "loop count: ",cnt if area_percent<0.8: continue if cnt > patch_num*10+1000: print "There is no moare patches to extract in this slide" print "mask region is too small" print "final number of patches : ",len(patch_list) break #patch,point is appended the list #print "region percent: ",area_percent patch_point.append((x_l[p_idx],y_l[p_idx])) patch=slide.read_region((y_ws[p_idx],x_ws[p_idx]),0,(patch_size,patch_size)) patch =np.array(patch) patch_list.append(cv2.cvtColor(patch,cv2.COLOR_RGBA2BGR)) return patch_list, patch_point