用COCOeval计算mask mAP

对于目标检测来说,cocoeval计算box mAP的过程可以如下,
先把预测的目标框坐标结合image_id dump到一个和coco annotation格式一样的json文件。
然后调用

coco_dets = self.coco_api.loadRes(json_path)
coco_eval = COCOeval(
    copy.deepcopy(self.coco_api), copy.deepcopy(coco_dets), "bbox" 
)
coco_eval.evaluate()
coco_eval.accumulate()

如果要计算mask的mAP, 需要把上面的“bbox”改成“segm”

coco_eval = COCOeval(
    copy.deepcopy(self.coco_api), copy.deepcopy(coco_dets), "segm" 
)

coco_api的loadRes函数里有这么一个处理,
如果没有把mask写进去,就会自动把目标框的4个点连接起来当作轮廓。

if not 'segmentation' in ann:
    ann['segmentation'] = [[x1, y1, x1, y2, x2, y2, x2, y1]]

annotation文件中segment也是以轮廓的polygon形式储存的。
coco annotation的格式

{
	"segmentation": [[510.66,423.01,511.72,420.03,510.45......]], #两两组成(x,y)坐标,polygon格式
	"area": 702.1057499999998, #面积
	"iscrowd": 0,  #是不是一群物体,为0是seg是polygon格式,否则是RLE格式
	"image_id": 289343,  #对应的image id
	"bbox": [473.07,395.93,38.65,28.67], #(x,y,w,h)
	"category_id": 18,  #分类label
	"id": 1768  #当前annotation的id,每一个图像有不止一个对象,所以要对每一个对象编号(每个对象的ID是唯一的)
},

而在coco.py中,可以看到polygon格式的segment要先转成RLE,再转为mask.

def annToMask(self, ann):
    """
    Convert annotation which can be polygons, uncompressed RLE, or RLE to binary mask.
    :return: binary mask (numpy 2D array)
    """
    rle = self.annToRLE(ann)
    m = maskUtils.decode(rle)

所以,segment的mask要以polygon或者RLE格式保存。
polygon格式踩了坑,这里说RLE格式。

需要把二值mask转成polygon/RLE形式,dump到json文件中,才能调用COCOeval函数。
mask转RLE的过程可以加到results2json函数中。

假设results里面存的是目标框和class这些。

    def results2json(self, results, mask):
        """
        results: {image_id: {label: [bboxes...] } }
        :return coco json format: {image_id:
                                   category_id:
                                   bbox:
                                   score: }
        """
        json_results = []
        for image_id, dets in results.items():
            for label, bboxes in dets.items():
                category_id = self.cat_ids[label]
                for bbox in bboxes:
                    score = float(bbox[4])
                    detection = dict(
                        image_id=int(image_id),
                        category_id=int(category_id),
                        #注意这里是tensor, int型的二值mask
                        segmentation=mask_to_rle(mask),  #这里把mask转为RLE
                        bbox=xyxy2xywh(bbox),
                        score=score,
                    )
                    json_results.append(detection)
        return json_results

mask转RLE的代码来自segment anything的utils.

    def mask_to_rle(tensor: torch.Tensor) -> List[Dict[str, Any]]:
        """
        Encodes masks to an uncompressed RLE, in the format expected by
        pycoco tools.
        """
        # Put in fortran order and flatten h,w
        h, w, b = tensor.shape  #需要根据tensor的shape修改
        tensor = tensor.permute(2, 1, 0).flatten(1)  #需要根据tensor的shape修改

        # Compute change indices
        diff = tensor[:, 1:] ^ tensor[:, :-1]
        change_indices = diff.nonzero()

        # Encode run length
        out = []
        for i in range(b):
            cur_idxs = change_indices[change_indices[:, 0] == i, 1]
            cur_idxs = torch.cat(
                [
                    torch.tensor([0], dtype=cur_idxs.dtype, device=cur_idxs.device),
                    cur_idxs + 1,
                    torch.tensor([h * w], dtype=cur_idxs.dtype, device=cur_idxs.device),
                ]
            )
            btw_idxs = cur_idxs[1:] - cur_idxs[:-1]
            counts = [] if tensor[i, 0] == 0 else [0]
            counts.extend(btw_idxs.detach().cpu().tolist())
            out.append({"size": [h, w], "counts": counts})
        return out

然后把上面得到的json给dump出来,再调用COCOeval函数就可以计算出mask mAP啦。

json.dump(results_json, open(json_path, "w"))
coco_dets = self.coco_api.loadRes(json_path)
coco_eval = COCOeval(
    copy.deepcopy(self.coco_api), copy.deepcopy(coco_dets), "segm"
)
coco_eval.evaluate()
coco_eval.accumulate()
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值