123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- import cv2
- import numpy as np
- def unmold_mask(mask, bbox, image_shape):
- """
- 将mask缩放到图像坐标系
- :param mask: [height, width] float型,通常较小
- :param bbox: [y1, x1, y2, x2] mask所在的box
- :param image_shape: 所需匹配的图像坐标
- :return: binary mask(图像尺寸为image_shape指定)
- """
- threshold = 0.5
- y1, x1, y2, x2 = bbox
- mask = cv2.resize(mask, (x2-x1, y2-y1))
- mask = np.where(mask >= threshold, 1, 0).astype(np.bool)
- # 将mask 放在正确的位置
- full_mask = np.zeros((int(image_shape[0]), int(image_shape[1])), dtype=np.bool)
- full_mask[y1:y2, x1:x2] = mask
- return full_mask
- def get_bounding_boxes(masks):
- num_masks = masks.shape[-1]
- bounding_boxes = np.zeros([num_masks, 4], dtype=np.int32)
- for i in range(num_masks):
- m = masks[:, :, i]
- horizontal_indicies = np.where(np.any(m, axis=0))[0]
- vertical_indicies = np.where(np.any(m, axis=1))[0]
- if horizontal_indicies.shape[0]:
- x1, x2 = horizontal_indicies[[0, -1]]
- y1, y2 = vertical_indicies[[0, -1]]
- x2 += 1
- y2 += 1
- else:
- x1, x2, y1, y2 = 0, 0, 0, 0
- bounding_boxes[i] = np.array([y1, x1, y2, x2])
- return bounding_boxes
- def compute_overlaps_masks(masks1, masks2):
- """
- 计算两组masks的重叠率
- :param masks1: [height, width, num_instance_1]
- :param masks2: [height, width, num_instance_2]
- :return:
- """
- # 任意一个输入为空,则返回结果为空
- if masks1.shape[-1] == 0 or masks2.shape[-1] == 0:
- return np.zeros((masks1.shape[-1], masks2.shape[-2]))
- # 展平,计算面积
- 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)
- # 计算IoU
- intersections = np.dot(masks1.T, masks2)
- union = area1[:, None] + area2[None, :] - intersections
- overlaps = intersections / union
- return overlaps
- def compute_ratio_masks_in_rect(masks, rect):
- """
- 计算每一个mask在rect中的面积比
- :param masks:
- :param rect: 未归一化
- :return:
- """
- num_mask = masks.shape[-1]
- ratios = np.zeros(num_mask, dtype=np.float32)
- for i in range(num_mask):
- area_mask = np.sum(masks[:, :, i])
- if area_mask <= 0:
- ratios[i] = 0
- area_in_rect = np.sum(masks[rect[1]: rect[3], rect[0]: rect[2], i])
- ratios[i] = area_in_rect/float(area_mask)
- return ratios
- def masks_center_in_rect(masks, rect):
- """
- 判断每一个mask的中心是否在rect以内
- :param masks:
- :param rect: 未归一化
- :return:
- """
- num_mask = masks.shape[-1]
- in_rect = np.zeros(num_mask, dtype=np.bool)
- for i in range(num_mask):
- inds = np.where(masks[:, :, i])
- if len(inds[0]) > 0:
- center_y = np.mean(inds[0])
- center_x = np.mean(inds[1])
- if (center_y >= rect[1]) and (center_y <= rect[3])\
- and (center_x >= rect[0]) and (center_x <= rect[2]):
- in_rect[i] = True
- return in_rect
- def clip_masks(masks, class_ids, clip_rect, in_rect=None):
- """
- 如果mask的中心不在clip_rect范围内,则直接去掉该标注,如果在clip_rect范围内,则只裁取clip_rect范围内的部分
- :param masks:
- :param class_ids:
- :param clip_rect:
- :param in_rect:
- :return:
- """
- if in_rect is None:
- in_rect = masks_center_in_rect(masks, clip_rect)
- num_mask = masks.shape[-1]
- clip_rect_height = clip_rect[3] - clip_rect[1]
- clip_rect_width = clip_rect[2] - clip_rect[0]
- clipped_masks = np.zeros((clip_rect_height, clip_rect_width, num_mask), dtype=masks.dtype)
- clipped_class_ids = np.zeros_like(class_ids)
- clipped_ind = 0
- for i in range(num_mask):
- if in_rect[i]:
- clipped_masks[:, :, clipped_ind] = masks[clip_rect[1]: clip_rect[3], clip_rect[0]: clip_rect[2], i]
- clipped_class_ids[clipped_ind] = class_ids[i]
- clipped_ind += 1
- return clipped_masks, clipped_class_ids
- def minimize_mask(bbox, mask, mini_shape):
- """Resize masks to a smaller version to reduce memory load.
- Mini-masks can be resized back to image scale using expand_masks()
- :param bbox: [num_gt, (y1, x1, y2, x2)] int32
- :param mask: [resize_height, resize_width, num_gt] uint8
- :param mini_shape: [mini_mask_height, mini_mask_width]
- """
- # H W C
- mini_height = mini_shape[0]
- mini_width = mini_shape[1]
- num_gt = mask.shape[-1]
- mini_mask = np.zeros((mini_height, mini_width, num_gt), dtype=np.uint8)
- for i in range(num_gt):
- m = mask[:, :, i].astype(np.uint8)
- y1, x1, y2, x2 = bbox[i][:4]
- m = m[y1:y2, x1:x2]
- if m.size == 0:
- m = np.zeros((mini_height, mini_width), dtype=np.uint8)
- else:
- m = cv2.resize(m, (mini_width, mini_height), 0, 0, interpolation=cv2.INTER_LINEAR)
- mini_mask[:, :, i] = np.around(m)
- return mini_mask
|