def IoU_per_score(gt_mask, gt_class_id, pred_mask): IoU_general = [] IoU_names = ["IoU", "IoU_ring", "IoU_crack", "IoU_resin", "IoU_pith"] # if no mask is detected if pred_mask.shape[-1] == 0: IoU_general = [0]*5 else: IoU= utils.compute_overlaps_masks(gt_mask, pred_mask) IoU = np.nan_to_num(np.mean(IoU)) #change nans to 0 IoU_general = [IoU] for i in range(1,5): IoU= utils.compute_overlaps_masks(gt_mask[:,:,gt_class_id==i], pred_mask[:,:,pred_class_id==i]) IoU = np.nan_to_num(np.mean(IoU)) #change nans to 0 IoU_general.append(IoU) return IoU_general, IoU_names
def compute_mean_iou_per_image(num_classes, pred_masks, gt_masks, matched_classes): ''' This function computes the average IoU per image. each image can contain different amount and kind of mask's classes, the average is taken among each class separately. :param num_classes: ndarray (1,num_images): how many classes exist in each image? (background doesn't count) :param pred_masks: the image's predicted masks :param gt_masks: the image's ground truth masks :param matched_classes: ndarray it's indices has correspondence between the prediction to the GT. :return IoU_per_class: mean IoU over all instances from the same class. ndarray with shape[num_classes + 1, 1] :return class_exist: ndarray with shape[num_classes + 1, 1], which contain 1 at indces where the class has at least one instance in the image ''' # IoU: mat. IoU score of each possible pair of masks gt Vs preds IoU = utils.compute_overlaps_masks(pred_masks, gt_masks) diag_indices = np.arange(IoU.shape[0]) # ndarray. IoU of matched masks IoU_diag = IoU[diag_indices, diag_indices] IoU_per_class = np.zeros((num_classes + 1, 1)) cnt_classes = np.zeros((num_classes + 1, 1)) for i in np.arange(IoU_diag.shape[0]): IoU_per_class[matched_classes[i]] += IoU_diag[i] cnt_classes[matched_classes[i]] += 1 select_nonzero = cnt_classes != 0 IoU_per_class[select_nonzero] = IoU_per_class[ select_nonzero] / cnt_classes[select_nonzero] class_exist = cnt_classes > 0 return IoU_per_class, class_exist.astype(np.uint8)
def TP_FP_FN_per_score_mask(gt_mask, pred_mask, scores, IoU_treshold): #loop scores score_range = np.arange(0.5, 1.0, 0.05) #print(gt_r) #print(pred_r) gt_rings = [] pred_rings = [] TPs = [] FPs = [] FNs = [] for SR in score_range: #print(SR) score_ids = np.where( scores > SR)[0] #Ids for predictions above certain score threshold #print(score_ids) mask_SR = np.take(pred_mask, score_ids, axis=2) #print('mask_SR.shape:', mask_SR.shape) mask_matrix = utils.compute_overlaps_masks(gt_mask, mask_SR) #print("mask_matrix", mask_matrix) #for every score range callculate TP, ...append by the socre ranges # making binary numpy array with IoU treshold mask_matrix_binary = np.where(mask_matrix > IoU_treshold, 1, 0) #print (mask_matrix_binary) #GT rings and predicted rigs #print(mask_matrix.shape) if mask_matrix.shape[0] == 0: TPs.append(0) FPs.append(0) FNs.append(0) else: gt_r = len(mask_matrix) pred_r = len(mask_matrix[0]) #TP sum_truth = np.sum(mask_matrix_binary, axis=1) sum_truth_binary = np.where(sum_truth > 0, 1, 0) TP = np.sum(sum_truth_binary) TPs.append(TP) #print('TPs:', TPs) #FP sum_pred = np.sum(mask_matrix_binary, axis=0) sum_pred_binary = np.where(sum_pred > 0, 1, 0) FP = pred_r - np.sum(sum_pred_binary) FPs.append(FP) #print('FP:', FP) #FN FN = gt_r - TP FNs.append(FN) #print('FN:', FN) #put together and sum up TP...per range return TPs, FPs, FNs, score_range
gt_mask_flat = gt_mask_flat + gt_mask[:,:,m] #print('combined_mask_shape:', combined_mask_binary.shape) gt_mask_flat_binary = np.where(gt_mask_flat > 0, 1, 0) #print(gt_mask_flat_binary.shape) gt_mask_flat_binary = np.reshape(gt_mask_flat_binary, (1024,1024,1)) print('gt_mask_shape:', gt_mask_flat_binary.shape) #### THIS SHOULD BE DONE ON INDIVIDUAL MASKS AND NOT ON FLATENED IoU_combined_mask.append(utils.compute_overlaps_masks(gt_mask_flat_binary, combined_mask_binary_wrong)) #IoU_combined_mask = np.mean(IoU_combined_mask) #print('IoU_combined:', IoU_combined_mask) """ mask_matrix = utils.compute_overlaps_masks(gt_mask, combined_mask_binary) print("mask_matrix.shape", mask_matrix.shape) print("mask_matrix", mask_matrix) # making binary numpy array with IoU treshold ## HERE YOU CAN CALCULATE FOR ALL IoU IoU_treshold = 0.5 # i set it less because combined mask is bigger and it does not matter i think mask_matrix_binary = np.where(mask_matrix > IoU_treshold, 1, 0) #print (mask_matrix_binary) #GT rings and predicted rigs gt_r = len(mask_matrix) pred_r = len(mask_matrix[0]) #TP sum_truth = np.sum(mask_matrix_binary, axis=1) sum_truth_binary = np.where(sum_truth > 0, 1, 0)
def compute_matches(gt_boxes, gt_class_ids, gt_masks, pred_boxes, pred_class_ids, pred_scores, pred_masks, iou_threshold=0.5, score_threshold=0.0): """Finds matches between prediction and ground truth instances. Returns: gt_match: 1-D array. For each GT box it has the index of the matched predicted box. pred_match: 1-D array. For each predicted box, it has the index of the matched ground truth box. overlaps: [pred_boxes, gt_boxes] IoU overlaps. """ # Trim zero padding # TODO: cleaner to do zero unpadding upstream gt_boxes = utils.trim_zeros(gt_boxes) gt_masks = gt_masks[..., :gt_boxes.shape[0]] pred_boxes = utils.trim_zeros(pred_boxes) pred_scores = pred_scores[:pred_boxes.shape[0]] # Sort predictions by score from high to low indices = np.argsort(pred_scores)[::-1] pred_boxes = pred_boxes[indices] pred_class_ids = pred_class_ids[indices] pred_scores = pred_scores[indices] pred_masks = pred_masks[..., indices] # Compute IoU overlaps [pred_masks, gt_masks] overlaps = utils.compute_overlaps_masks(pred_masks, gt_masks) masks1 = pred_masks masks2 = gt_masks masks1 = np.reshape(masks1 > .5, (-1, masks1.shape[-1])).astype(np.float32) masks2 = np.reshape(masks2 > .5, (-1, masks2.shape[-1])).astype(np.float32) area1 = np.sum(masks1, axis=0) area2 = np.sum(masks2, axis=0) # intersections and union intersections = np.dot(masks1.T, masks2) gt_class_area = np.zeros(3) for i, ids in enumerate(gt_class_ids): gt_class_area[ids] += area2[i] # Loop through predictions and find matching ground truth boxes match_count = 0 pred_match = -1 * np.ones([pred_boxes.shape[0]]) gt_match = -1 * np.ones([gt_boxes.shape[0]]) for i in range(len(pred_boxes)): # Find best matching ground truth box # 1. Sort matches by score sorted_ixs = np.argsort(overlaps[i])[::-1] # 2. Remove low scores low_score_idx = np.where(overlaps[i, sorted_ixs] < score_threshold)[0] if low_score_idx.size > 0: sorted_ixs = sorted_ixs[:low_score_idx[0]] # 3. Find the match for j in sorted_ixs: # If ground truth box is already matched, go to next one if gt_match[j] > 0: continue # If we reach IoU smaller than the threshold, end the loop iou = overlaps[i, j] if iou < iou_threshold: break # Do we have a match? if pred_class_ids[i] == gt_class_ids[j]: match_count += 1 gt_match[j] = i pred_match[i] = j break return gt_match, pred_match, overlaps, gt_class_area, area1, intersections
def TP_FP_FN_IoU_per_score_mask(gt_mask, pred_mask, scores, IoU_threshold, score_range=None): #loop scores if score_range is None: score_range = np.arange(0.5, 1.0, 0.05) #print(gt_r) #print(pred_r) TPs = [] FPs = [] FNs = [] IoUs = [] #print("GT_MASK_SHAPE", gt_mask.shape) for SR in score_range: #print("SR",SR) #print("scores", scores) score_ids = np.where(scores > SR)[0] #Ids for predictions above certain score threshold #print("score_ids", score_ids) #print("pred_mask.shape", pred_mask.shape) mask_SR = np.take(pred_mask, score_ids, axis=2) #print('mask_SR.shape:', mask_SR.shape) mask_matrix = utils.compute_overlaps_masks(gt_mask, mask_SR) print("mask_matrix", mask_matrix) # calculate average IoU IoU_clean = mask_matrix[np.where(mask_matrix>0)] #print("IoU_clean", IoU_clean) IoU = np.nan_to_num(np.mean(IoU_clean)) IoUs.append(IoU) #for every score range callculate TP, ...append by the socre ranges # making binary numpy array with IoU threshold mask_matrix_binary = np.where(mask_matrix > IoU_threshold, 1, 0) #print("mask_matrix_binary", mask_matrix_binary) #GT rings and predicted rigs #print("MASK MATRIX SHAPE", mask_matrix.shape) if mask_matrix.shape[0]==0: TPs.append(0) FPs.append(mask_SR.shape[-1]) # All predicted are false in this case FNs.append(0) else: gt_r = len(mask_matrix) pred_r = len(mask_matrix[0]) #TP sum_truth = np.sum(mask_matrix_binary, axis=1) sum_truth_binary = np.where(sum_truth > 0, 1, 0) TP = np.sum(sum_truth_binary) TPs.append(TP) #print('TP:', TP) #FP sum_pred = np.sum(mask_matrix_binary, axis=0) sum_pred_binary = np.where(sum_pred > 0, 1, 0) FP = pred_r - np.sum(sum_pred_binary) FPs.append(FP) #print('FP:', FP) #FN FN = gt_r - TP FNs.append(FN) print('TPs:', TPs) print('FPs:', FPs) print('FNs:', FNs) #put together and sum up TP...per range return TPs, FPs, FNs, IoUs
def TP_FP_FN_IoU_comb(gt_mask, pred_mask, IoU_thresholds=None): #loop scores if IoU_thresholds is None: IoU_thresholds = np.arange(0, 1.0, 0.05) #print(gt_r) #print(pred_r) TPs = [] FPs = [] FNs = [] IoUs = [] #print("GT_MASK_SHAPE", gt_mask.shape) for iou_threshold in IoU_thresholds: mask_matrix = utils.compute_overlaps_masks(gt_mask, pred_mask) print("combined_mask_matrix", mask_matrix) if iou_threshold == min(IoU_thresholds): # calculate average IoU IoU_clean = mask_matrix[np.where(mask_matrix>0)] #print("IoU_clean", IoU_clean) IoU = np.nan_to_num(np.mean(IoU_clean)) IoUs.append(IoU) #for every score range callculate TP, ...append by the socre ranges # making binary numpy array with IoU threshold mask_matrix_binary = np.where(mask_matrix > iou_threshold, 1, 0) #print ("comb_mask_matrix_binary", mask_matrix_binary) #GT rings and predicted rigs #print("MASK MATRIX SHAPE", mask_matrix.shape) if mask_matrix.shape[0]==0: TPs.append(0) FPs.append(pred_mask.shape[-1]) # All predicted are false in this case FNs.append(0) else: gt_r = len(mask_matrix) pred_r = len(mask_matrix[0]) #TP sum_truth = np.sum(mask_matrix_binary, axis=1) sum_truth_binary = np.where(sum_truth > 0, 1, 0) TP = np.sum(sum_truth_binary) TPs.append(TP) #print('TP:', TP) #FP sum_pred = np.sum(mask_matrix_binary, axis=0) sum_pred_binary = np.where(sum_pred > 0, 1, 0) FP = pred_r - np.sum(sum_pred_binary) FPs.append(FP) #print('FP:', FP) #FN FN = gt_r - TP FNs.append(FN) print('TPs:', TPs) print('FPs:', FPs) print('FNs:', FNs) #put together and sum up TP...per range return TPs, FPs, FNs, IoUs
model.load_weights(custom_WEIGHTS_PATH, by_name=True) from importlib import reload # was constantly changin the visualization, so I decided to reload it instead of notebook reload(visualize) image_id = int(sys.argv[1]) image, image_meta, gt_class_id, gt_bbox, gt_mask =\ modellib.load_image_gt(dataset, config, image_id, use_mini_mask=False) info = dataset.image_info[image_id] #print("image ID: {}.{} ({}) {}".format(info["source"], info["id"], image_id, # dataset.image_reference(image_id))) # Run object detection results = model.detect([image], verbose=1) # Display results ax = get_ax(1) r = results[0] visualize.display_differences visualize.display_instances(image, r['rois'], r['masks'], r['class_ids'], dataset.class_names, r['scores'], ax=ax, title="Predictions") iou = utils.compute_overlaps_masks(gt_mask, r['masks']) print("IOU:" + str(iou))
gt_mask = gt_mask[:, :, gt_class_id == 1] nmasks = gt_mask.shape[2] for m in range(0, nmasks): gt_mask_flat = gt_mask_flat + gt_mask[:, :, m] #calcumate IoU combined_mask_binary = np.where(combined_mask > 0, 1, 0) #print("combined_mask_binary",combined_mask_binary.shape) combined_mask_binary = np.reshape(combined_mask_binary, (1024, 1024, 1)) #print('combined_mask_shape:', combined_mask_binary.shape) gt_mask_flat_binary = np.where(gt_mask_flat > 0, 1, 0) #print(gt_mask_flat_binary.shape) gt_mask_flat_binary = np.reshape(gt_mask_flat_binary, (1024, 1024, 1)) print('gt_mask_shape:', gt_mask_flat_binary.shape) IoU_combined_mask.append( utils.compute_overlaps_masks(gt_mask_flat_binary, combined_mask_binary)) #IoU_combined_mask = np.mean(IoU_combined_mask) #print('IoU_combined:', IoU_combined_mask) ####### Try to separate combined masks into layers separated_mask = modify_flat_mask(combined_mask) #print('separated_mask_shape', separated_mask.shape) #print(IoU_m) #plt.imshow(gt_mask[:,:,3]) #plt.show() #plt.imshow(separated_mask[:,:,0]) #plt.show() mask_matrix = utils.compute_overlaps_masks(gt_mask, separated_mask) #print("mask_matrix.shape", mask_matrix.shape)
###calculate all the stuff mask_normal = r['masks'] # for the combined mask at the end ap = utils.compute_ap_range(gt_bbox, gt_class_id, gt_mask, r['rois'], r['class_ids'], r['scores'], r['masks'], verbose=0) #print(r['scores']) #print(r['masks'].shape) mAP.append(ap) #compute mask IoU IoU_m = utils.compute_overlaps_masks(gt_mask, r['masks']) IoU_m = np.nan_to_num(np.mean(IoU_m)) #change nans to 0 mask_IoU.append(IoU_m) #compute bbox IoU IoU_bbox = utils.compute_overlaps(gt_bbox, r['rois']) IoU_bbox = np.nan_to_num(np.mean(IoU_bbox)) bbox_IoU.append(IoU_bbox) #compute TP, FP, FN for mask TP, FP, FN, score_range = TP_FP_NF_per_score_mask(gt_mask, r['masks'], r['scores'], IoU_treshold=0.3) #print(TP) #print(FP)
def display_instances(image, boxes, masks, mask1, class_ids, class_names, scores=None, title="", figsize=(16, 16), ax=None): """ boxes: [num_instance, (y1, x1, y2, x2, class_id)] in image coordinates. masks: [height, width, num_instances] class_ids: [num_instances] class_names: list of class names of the dataset scores: (optional) confidence scores for each box figsize: (optional) the size of the image. """ # Number of instances N = boxes.shape[0] mask_iou_bf = [] mask_iou_plaque = [] if not N: print("\n*** No instances to display *** \n") else: assert boxes.shape[0] == masks.shape[-1] == class_ids.shape[0] if not ax: _, ax = plt.subplots(1, figsize=figsize) # Generate random colors colors = random_colors(N) # Show area outside image boundaries. height, width = image.shape[:2] ax.set_ylim(height + 10, -10) ax.set_xlim(-10, width + 10) ax.axis('off') ax.set_title(title) masked_image = image.astype(np.uint32).copy() for i in range(N): color = colors[i] # Bounding box if not np.any(boxes[i]): # Skip this instance. Has no bbox. Likely lost in image cropping. continue y1, x1, y2, x2 = boxes[i] p = patches.Rectangle((x1, y1), x2 - x1, y2 - y1, linewidth=2, alpha=0.7, linestyle="-", edgecolor=color, facecolor='none') ax.add_patch(p) # Label class_id = class_ids[i] score = scores[i] if scores is not None else None label = class_names[class_id] x = random.randint(x1, (x1 + x2) // 2) caption = "{} {:.3f}".format(label, score) if score else label ax.text(x1, y1 - 10, caption, color=color, size=11, backgroundcolor="none") # Mask iou_acc = compute_overlaps_masks(masks, mask1) ax.text(x1 - 7, y1 - 86 + (38 * i), "mask_iou for {} :{}".format(label, max(np.array(iou_acc[i])))) if label == 'leaf': mask_iou_bf.append(max(np.array(iou_acc[i]))) elif label == 'root': mask_iou_plaque.append(max(np.array(iou_acc[i]))) mask = masks[:, :, i] #mask1 = mask1[:,:,i] masked_image = apply_mask(masked_image, mask, color) #masks_img = apply_mask(masking_image,mask1,color) # Mask Polygon # Pad to ensure proper polygons for masks that touch image edges. padded_mask = np.zeros((mask.shape[0] + 2, mask.shape[1] + 2), dtype=np.uint8) #padding_mask = np.zeros((mask1.shape[0]+2,mask1.shape[1]+2),dtype=np.uint8) padded_mask[1:-1, 1:-1] = mask #padding_mask[1:-1,1:-1] = mask1 contours = find_contours(padded_mask, 0.5) #contouring = find_contours(padding_mask,0.5) for verts in contours: # Subtract the padding and flip (y, x) to (x, y) verts = np.fliplr(verts) - 1 p = Polygon(verts, facecolor="none", edgecolor=color) ax.add_patch(p) #parr = np.array(parr) '''ax.text(x1, y1-2, "Area:{}".format(math.ceil(area(verts))), color='w', size=11, backgroundcolor="none")''' #ax.text(x1-7, y1-56,"mask_iou:{}".format(compute_overlaps_masks(masks, mask1), color='w', size=11, backgroundcolor='none')) #print(np.array(verts).shape) ax.imshow(masked_image.astype(np.uint8)) plt.show() return [np.mean(np.array(mask_iou_bf)), np.mean(np.array(mask_iou_plaque))]