import cv2 import numpy as np import random import math try: from util.de_transform import perturb_seg except: from de_transform import perturb_seg def modify_boundary(image, regional_sample_rate=0.1, sample_rate=0.1, move_rate=0.0, iou_target = 0.8): # modifies boundary of the given mask. # remove consecutive vertice of the boundary by regional sample rate # -> # remove any vertice by sample rate # -> # move vertice by distance between vertice and center of the mask by move rate. # input: np array of size [H,W] image # output: same shape as input # get boundaries if int(cv2.__version__[0]) >= 4: contours, _ = cv2.findContours(image, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) else: _, contours, _ = cv2.findContours(image, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) #only modified contours is needed actually. sampled_contours = [] modified_contours = [] for contour in contours: if contour.shape[0] < 10: continue M = cv2.moments(contour) #remove region of contour number_of_vertices = contour.shape[0] number_of_removes = int(number_of_vertices * regional_sample_rate) idx_dist = [] for i in range(number_of_vertices-number_of_removes): idx_dist.append([i, np.sum((contour[i] - contour[i+number_of_removes])**2)]) idx_dist = sorted(idx_dist, key=lambda x:x[1]) remove_start = random.choice(idx_dist[:math.ceil(0.1*len(idx_dist))])[0] #remove_start = random.randrange(0, number_of_vertices-number_of_removes, 1) new_contour = np.concatenate([contour[:remove_start], contour[remove_start+number_of_removes:]], axis=0) contour = new_contour #sample contours number_of_vertices = contour.shape[0] indices = random.sample(range(number_of_vertices), int(number_of_vertices * sample_rate)) indices.sort() sampled_contour = contour[indices] sampled_contours.append(sampled_contour) modified_contour = np.copy(sampled_contour) if (M['m00'] != 0): center = round(M['m10'] / M['m00']), round(M['m01'] / M['m00']) #modify contours for idx, coor in enumerate(modified_contour): change = np.random.normal(0,move_rate) # 0.1 means change position of vertex to 10 percent farther from center x,y = coor[0] new_x = x + (x-center[0]) * change new_y = y + (y-center[1]) * change modified_contour[idx] = [new_x,new_y] modified_contours.append(modified_contour) #draw boundary gt = np.copy(image) image = np.zeros_like(image) modified_contours = [cont for cont in modified_contours if len(cont) > 0] if len(modified_contours) == 0: image = gt.copy() else: image = cv2.drawContours(image, modified_contours, -1, (255, 0, 0), -1) image = perturb_seg(image, iou_target) return image