mirror of
https://github.com/deepinsight/insightface.git
synced 2025-12-30 08:02:27 +00:00
243 lines
7.9 KiB
Python
243 lines
7.9 KiB
Python
#!/usr/bin/env python
|
|
# -*- encoding: utf-8 -*-
|
|
"""
|
|
@Author : Qingping Zheng
|
|
@Contact : qingpingzheng2014@gmail.com
|
|
@File : miou.py
|
|
@Time : 10/01/21 00:00 PM
|
|
@Desc :
|
|
@License : Licensed under the Apache License, Version 2.0 (the "License");
|
|
@Copyright : Copyright 2022 The Authors. All Rights Reserved.
|
|
"""
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
import argparse
|
|
import cv2
|
|
import json
|
|
import numpy as np
|
|
import os
|
|
|
|
from collections import OrderedDict
|
|
from PIL import Image as PILImage
|
|
from utils.transforms import transform_parsing
|
|
|
|
|
|
LABELS = ['background', 'skin', 'nose', 'eye_g', 'l_eye', 'r_eye', \
|
|
'l_brow', 'r_brow', 'l_ear', 'r_ear', 'mouth', 'u_lip', \
|
|
'l_lip', 'hair', 'hat', 'ear_r', 'neck_l', 'neck', 'cloth']
|
|
|
|
|
|
def get_palette(num_cls):
|
|
""" Returns the color map for visualizing the segmentation mask.
|
|
Args:
|
|
num_cls: Number of classes
|
|
Returns:
|
|
The color map
|
|
"""
|
|
|
|
n = num_cls
|
|
palette = [0] * (n * 3)
|
|
for j in range(0, n):
|
|
lab = j
|
|
palette[j * 3 + 0] = 0
|
|
palette[j * 3 + 1] = 0
|
|
palette[j * 3 + 2] = 0
|
|
i = 0
|
|
while lab:
|
|
palette[j * 3 + 0] |= (((lab >> 0) & 1) << (7 - i))
|
|
palette[j * 3 + 1] |= (((lab >> 1) & 1) << (7 - i))
|
|
palette[j * 3 + 2] |= (((lab >> 2) & 1) << (7 - i))
|
|
i += 1
|
|
lab >>= 3
|
|
return palette
|
|
|
|
|
|
def get_confusion_matrix(gt_label, pred_label, num_classes):
|
|
"""
|
|
Calcute the confusion matrix by given label and pred
|
|
:param gt_label: the ground truth label
|
|
:param pred_label: the pred label
|
|
:param num_classes: the nunber of class
|
|
:return: the confusion matrix
|
|
"""
|
|
index = (gt_label * num_classes + pred_label).astype('int32')
|
|
label_count = np.bincount(index)
|
|
confusion_matrix = np.zeros((num_classes, num_classes))
|
|
|
|
for i_label in range(num_classes):
|
|
for i_pred_label in range(num_classes):
|
|
cur_index = i_label * num_classes + i_pred_label
|
|
if cur_index < len(label_count):
|
|
confusion_matrix[i_label, i_pred_label] = label_count[cur_index]
|
|
|
|
return confusion_matrix
|
|
|
|
|
|
def fast_histogram(a, b, na, nb):
|
|
'''
|
|
fast histogram calculation
|
|
---
|
|
* a, b: non negative label ids, a.shape == b.shape, a in [0, ... na-1], b in [0, ..., nb-1]
|
|
'''
|
|
assert a.shape == b.shape
|
|
assert np.all((a >= 0) & (a < na) & (b >= 0) & (b < nb))
|
|
# k = (a >= 0) & (a < na) & (b >= 0) & (b < nb)
|
|
hist = np.bincount(
|
|
nb * a.reshape([-1]).astype(int) + b.reshape([-1]).astype(int),
|
|
minlength=na * nb).reshape(na, nb)
|
|
assert np.sum(hist) == a.size
|
|
return hist
|
|
|
|
|
|
def _read_names(file_name):
|
|
label_names = []
|
|
for name in open(file_name, 'r'):
|
|
name = name.strip()
|
|
if len(name) > 0:
|
|
label_names.append(name)
|
|
return label_names
|
|
|
|
|
|
def _merge(*list_pairs):
|
|
a = []
|
|
b = []
|
|
for al, bl in list_pairs:
|
|
a += al
|
|
b += bl
|
|
return a, b
|
|
|
|
|
|
def compute_mean_ioU(preds, scales, centers, num_classes, datadir, input_size=[473, 473], dataset='val', reverse=False):
|
|
file_list_name = os.path.join(datadir, dataset + '_list.txt')
|
|
val_id = [line.split()[0][7:-4] for line in open(file_list_name).readlines()]
|
|
|
|
confusion_matrix = np.zeros((num_classes, num_classes))
|
|
|
|
label_names_file = os.path.join(datadir, 'label_names.txt')
|
|
gt_label_names = pred_label_names = _read_names(label_names_file)
|
|
|
|
assert gt_label_names[0] == pred_label_names[0] == 'bg'
|
|
|
|
hists = []
|
|
for i, im_name in enumerate(val_id):
|
|
gt_path = os.path.join(datadir, dataset, 'labels', im_name + '.png')
|
|
gt = cv2.imread(gt_path, cv2.IMREAD_GRAYSCALE)
|
|
h, w = gt.shape
|
|
pred_out = preds[i]
|
|
if scales is not None:
|
|
s = scales[i]
|
|
c = centers[i]
|
|
else:
|
|
s = None
|
|
c = None
|
|
pred_old = transform_parsing(pred_out, c, s, w, h, input_size)
|
|
gt = np.asarray(gt, dtype=np.int32)
|
|
pred = np.asarray(pred_old, dtype=np.int32)
|
|
ignore_index = gt != 255
|
|
|
|
gt = gt[ignore_index]
|
|
pred = pred[ignore_index]
|
|
|
|
hist = fast_histogram(gt, pred, len(gt_label_names), len(pred_label_names))
|
|
hists.append(hist)
|
|
|
|
confusion_matrix += get_confusion_matrix(gt, pred, num_classes)
|
|
|
|
hist_sum = np.sum(np.stack(hists, axis=0), axis=0)
|
|
|
|
eval_names = dict()
|
|
for label_name in gt_label_names:
|
|
gt_ind = gt_label_names.index(label_name)
|
|
pred_ind = pred_label_names.index(label_name)
|
|
eval_names[label_name] = ([gt_ind], [pred_ind])
|
|
|
|
if 'le' in eval_names and 're' in eval_names:
|
|
eval_names['eyes'] = _merge(eval_names['le'], eval_names['re'])
|
|
if 'lb' in eval_names and 'rb' in eval_names:
|
|
eval_names['brows'] = _merge(eval_names['lb'], eval_names['rb'])
|
|
if 'ulip' in eval_names and 'imouth' in eval_names and 'llip' in eval_names:
|
|
eval_names['mouth'] = _merge(
|
|
eval_names['ulip'], eval_names['imouth'], eval_names['llip'])
|
|
|
|
# Helen
|
|
if 'eyes' in eval_names and 'brows' in eval_names and 'nose' in eval_names and 'mouth' in eval_names:
|
|
eval_names['overall'] = _merge(
|
|
eval_names['eyes'], eval_names['brows'], eval_names['nose'], eval_names['mouth'])
|
|
|
|
pos = confusion_matrix.sum(1)
|
|
res = confusion_matrix.sum(0)
|
|
tp = np.diag(confusion_matrix)
|
|
|
|
pixel_accuracy = (tp.sum() / pos.sum()) * 100
|
|
mean_accuracy = ((tp / np.maximum(1.0, pos)).mean()) * 100
|
|
IoU_array = (tp / np.maximum(1.0, pos + res - tp))
|
|
IoU_array = IoU_array * 100
|
|
mean_IoU = IoU_array.mean()
|
|
print('Pixel accuracy: %f \n' % pixel_accuracy)
|
|
print('Mean accuracy: %f \n' % mean_accuracy)
|
|
print('Mean IU: %f \n' % mean_IoU)
|
|
mIoU_value = []
|
|
f1_value = []
|
|
mf1_value = []
|
|
|
|
for i, (label, iou) in enumerate(zip(LABELS, IoU_array)):
|
|
mIoU_value.append((label, iou))
|
|
|
|
mIoU_value.append(('Pixel accuracy', pixel_accuracy))
|
|
mIoU_value.append(('Mean accuracy', mean_accuracy))
|
|
mIoU_value.append(('Mean IU', mean_IoU))
|
|
mIoU_value = OrderedDict(mIoU_value)
|
|
|
|
for eval_name, (gt_inds, pred_inds) in eval_names.items():
|
|
A = hist_sum[gt_inds, :].sum()
|
|
B = hist_sum[:, pred_inds].sum()
|
|
intersected = hist_sum[gt_inds, :][:, pred_inds].sum()
|
|
f1 = 2 * intersected / (A + B)
|
|
|
|
if eval_name in gt_label_names[1:]:
|
|
mf1_value.append(f1)
|
|
f1_value.append((eval_name, f1))
|
|
|
|
f1_value.append(('Mean_F1', np.array(mf1_value).mean()))
|
|
f1_value = OrderedDict(f1_value)
|
|
|
|
return mIoU_value, f1_value
|
|
|
|
|
|
def write_results(preds, scales, centers, datadir, dataset, result_dir, input_size=[473, 473]):
|
|
palette = get_palette(20)
|
|
if not os.path.exists(result_dir):
|
|
os.makedirs(result_dir)
|
|
|
|
json_file = os.path.join(datadir, 'annotations', dataset + '.json')
|
|
with open(json_file) as data_file:
|
|
data_list = json.load(data_file)
|
|
data_list = data_list['root']
|
|
for item, pred_out, s, c in zip(data_list, preds, scales, centers):
|
|
im_name = item['im_name']
|
|
w = item['img_width']
|
|
h = item['img_height']
|
|
pred = transform_parsing(pred_out, c, s, w, h, input_size)
|
|
|
|
save_path = os.path.join(result_dir, im_name[:-4]+'.png')
|
|
output_im = PILImage.fromarray(np.asarray(pred, dtype=np.uint8))
|
|
output_im.putpalette(palette)
|
|
output_im.save(save_path)
|
|
|
|
|
|
def get_arguments():
|
|
"""Parse all the arguments provided from the CLI.
|
|
|
|
Returns:
|
|
A list of parsed arguments.
|
|
"""
|
|
parser = argparse.ArgumentParser(description="DeepLabLFOV NetworkEv")
|
|
parser.add_argument("--pred-path", type=str, default='',
|
|
help="Path to predicted segmentation.")
|
|
parser.add_argument("--gt-path", type=str, default='',
|
|
help="Path to the groundtruth dir.")
|
|
|
|
return parser.parse_args()
|