一.基本思路
最近在整理小目标的检测和分割的方法的时候,想到了基于目标面积加权的一种思路,现在记录下,后面有机会验证下,基本思路如下:
- 1.找到mask里所有的目标轮廓
- 2.计算所有poly的面积
- 3.自适应阈值比例判断哪些是小物体
- 4.重新填充这些小物体
- 5.拿到新的mask后映射为权重图
- 6.根据权重图对CE进行小目标加权
二.源代码
import cv2
import numpy as np
import random
import torch
import matplotlib.pyplot as plt
AREA_THS = 30
def mask_small_object(mask, area_thresh, pixels=[0, 1, 2], weights=[0.5, 1.0, 10.0]):
"""
:param mask: 输入mask掩码
:param area_thresh: 小物体的阈值,面积小于该值认为是小物体
:param pixels: 背景 小物体 大物体的mask值
:param weight: 背景,前景大物体,前景小物体的权重
:return: 权重图
"""
contours, hierarchy = cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
area = []
for i in range(len(contours)):
area.append(cv2.contourArea(contours[i]))
for i in range(len(area)):
if area[i] < area_thresh:
cv2.fillPoly(mask, [contours[i]], (2, ))
for i in range(len(pixels)):
mask[mask==[pixels[i]]] = weights[i]
return mask
def mask_cross_entropy(y, y_hat, weight):
n = 1e-7
# return -np.sum(y * np.log(y_hat + n) + (1 - y) * np.log(1 - y_hat + n), axis=1)
assert y.shape == y_hat.shape
entro = (y * np.log(y_hat + n) + (1 - y) * np.log(1 - y_hat + n))
mask_entro = entro * weight
res = -np.mean(mask_entro)
return round(res, 5)
if __name__ == '__main__':
AREA_THS = 30
img = np.zeros(shape=(512, 512, 3), dtype=np.uint8)
label = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
for i in range(10):
x, y = random.randint(10, 500), random.randint(10, 500)
r = random.randint(1, 10)
cv2.circle(label, (x, y), radius=r, color=(1), thickness=-1)
weight = mask_small_object(label, area_thresh=AREA_THS)
pred = np.abs(np.random.rand(512, 512))
print(mask_cross_entropy(label, pred, weight))