嘘~ 正在从服务器偷取页面 . . .

数据集标注和评价指标


数据集标注

开放数据标注工具浅析

包括:labelme labelImg VIA 精灵标注 LabelHub

ps:ps标注可以选择使用磁性套索或者其他工具,标注完之后就涂色就可以了,自己设计一种颜色,比如urban street scene现在多此采用cityscapes的涂色方案。然后在使用的时候,把不同的rgb映射到类别空间,也就是灰度空间就可以了。一般,rgb是为了更好的结果类别的展示,训练的时候使用的是灰度图像。

labelme标注详解

Labelme的github地址 Labelme教程1 Labelme教程2

1下载安装labelme

##################
## for Python 3 ##
##################
#使用Anaconda创建虚拟环境
conda create --name=labelme python=3.6
source activate labelme
pip install pyqt5  # pyqt5 can be installed via pip on python3
pip install labelme

2打开labelme

打开anaconda Prompt

image-20210116145819793

3标注

使用open或opendir打开一张图片或一个文件夹

使用create polygons创建多边形标注即可

4转换

start labelme_json_to_dataset 1.json

py文件在路径:envs\labelme\Lib\site-packages\labelme\cli

labelme打不开,不显示主界面,之前使用扩展屏幕的原因,憨憨的

labelme_json_to_dataset.exe转换json生成的文件夹为空,原因是json内存储的文件路径的原因!!!!

评价指标

F1、IoU等计算方式理解与代码实现.

mIoU

PA

$$
PA=\frac{TP+TN}{TP+TN+FP+FN}\
PA=\frac{\sum_{i=0}^kp_{ii}}{\sum_{i=0}^k\sum_{j=0}^kp_{ij}}
$$

共有$k+1$个类,其中包含一个空类或背景,$p_{ij}$表示GT为i预测为j

Mean Pixel Accuracy(MAP,均像素精度):是PA的一种简单提升,计算每个类内被正确分类像素数的比例,之后求所有类的平均
$$
MPA=\frac{1}{k+1}\sum^k_{i=0}\frac{p_{ii}}{\sum^k_{j=0}p_{ij}}
$$

mIoU

Why?mIoU的优点

https://towardsdatascience.com/metrics-to-evaluate-your-semantic-segmentation-model-6bcb99639aa2

直观理解

在每个类上计算IoU,然后直接取平均

所以如果某个几个特定类的效果很差的话,会影响很大!
$$
MIoU=\frac{1}{k+1}\sum^k_{i=0}\frac{TP}{FN+FP+TP}\
MIoU=\frac{1}{k+1}\sum^k_{i=0}\frac{p_{ii}}{\sum^k_{j=0}p_{ij}+\sum^k_{j=0}p_{ji}-p_{ii}}
$$

来自AdaptSeg的源码

import json
import argparse
import numpy as np
from PIL import Image
from os.path import join


def fast_hist(a, b, n):
    # 获得布尔数组,只计算0-18,不计算255
    k = (a >= 0) & (a < n)
    # 每一行代表一类,该行对角线上的全是正确预测的,其余都是错误预测的
    return np.bincount(n * a[k].astype(int) + b[k], minlength=n ** 2).reshape(n, n)


def per_class_iu(hist):
    # 分子是第i类所有预测正确的,分母是第i类所有预测正确的+将第i类预测为其它类的+将其他类预测为第i类的,就是每一类的IoU
    return np.diag(hist) / (hist.sum(1) + hist.sum(0) - np.diag(hist))


def label_mapping(input, mapping):
    output = np.copy(input)
    for ind in range(len(mapping)):
        output[input == mapping[ind][0]] = mapping[ind][1]
    return np.array(output, dtype=np.int64)


def compute_mIoU(gt_dir, pred_dir, devkit_dir=''):
    """
    Compute IoU given the predicted colorized images and 
    """
    # 加载json数据
    with open(join(devkit_dir, 'info.json'), 'r') as fp:
        info = json.load(fp)
    # 19
    num_classes = np.int(info['classes'])
    print('Num classes', num_classes)
    # 类别标签
    name_classes = np.array(info['label'], dtype=np.str)
    # 原始标签到训练标签的映射
    mapping = np.array(info['label2train'], dtype=np.int)
    # (19,19)
    hist = np.zeros((num_classes, num_classes))
    # 获取gt图片和pred图片路径的列表
    image_path_list = join(devkit_dir, 'zurich_val.txt')
    label_path_list = join(devkit_dir, 'label_zurich.txt')
    gt_imgs = open(label_path_list, 'r').read().splitlines()
    gt_imgs = [join(gt_dir, x) for x in gt_imgs]
    pred_imgs = open(image_path_list, 'r').read().splitlines()
    pred_imgs = [join(pred_dir, x.split('/')[-1]) for x in pred_imgs]

    for ind in range(len(gt_imgs)):
        # 获取预测图片和标签图片
        pred = np.array(Image.open(pred_imgs[ind]))
        label = np.array(Image.open(gt_imgs[ind]))
        # 原始标签到训练标签的映射
        label = label_mapping(label, mapping)
        # 拉成一维比较,确认维数是否一致,原始都是(1080,1920),是'L' mode
        if len(label.flatten()) != len(pred.flatten()):
            print('Skipping: len(gt) = {:d}, len(pred) = {:d}, {:s}, {:s}'.format(len(label.flatten()),
                                                                                  len(pred.flatten()),                                                                                     gt_imgs[ind],
                                                                                  pred_imgs[ind]))
            continue
        # 计算IoU
        hist += fast_hist(label.flatten(), pred.flatten(), num_classes)
        # if ind > 0 and ind % 10 == 0:
        #     print('{:d} / {:d}: {:0.2f}'.format(ind, len(gt_imgs), 100*np.mean(per_class_iu(hist))))
    # 计算mIou
    mIoUs = per_class_iu(hist)
    for ind_class in range(num_classes):
        print('===>' + name_classes[ind_class] + ':\t' + str(round(mIoUs[ind_class] * 100, 2)) + '%')
    print('===> mIoU: ' + str(round(np.nanmean(mIoUs) * 100, 2)) + '%')
    return mIoUs


def main(args):
    compute_mIoU(args.gt_dir, args.pred_dir, args.devkit_dir)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    # GT路径、预测路径、存放不同数据集文件名索引的文件夹
    parser.add_argument('--gt_dir', default='./path/to/Dark_Zurich_val_anon/', type=str,
                        help='directory which stores CityScapes val gt images')
    parser.add_argument('--pred_dir', default='./result/dannet_PSPNet', type=str,
                        help='directory which stores CityScapes val pred images')
    parser.add_argument('--devkit_dir', default='./dataset/lists', help='base directory of cityscapes')
    args = parser.parse_args()
    main(args)

Dice coefficient

和mIou的区别https://stats.stackexchange.com/questions/273537/f1-dice-score-vs-iou/276144#276144

https://blog.csdn.net/JMU_Ma/article/details/97533768

https://zhuanlan.zhihu.com/p/269592183

def dice_loss(target,predictive,ep=1e-8):
    intersection = 2 * torch.sum(predictive * target) + ep
    union = torch.sum(predictive) + torch.sum(target) + ep
    loss = 1 - intersection / union
    return loss

Hausdorff distance

https://blog.csdn.net/lijiaqi0612/article/details/113925215\
$$
H(A,B)=max(h(A,B),h(B,A))
$$
可以直接用scipy的函数计算

scipy.spatial.distance.directed_hausdorff

数据集介绍

PASCAL VOC2010

Pascal Visual Object Classes,简称Pascal VOC数据集

VOC 2010

JPEGImages是原图,SegmentationClass是标准出每一个像素的类别,也就是语义分割的label,SegmentationObject是标注出每一个像素属于哪一个物体,也就是实例分割的label,Annotations目标检测的标注

image-20210426204731505

ImageSets是划分,跟我们相关的主要是Segmentation,

image-20210426204828552

里面是train,val和trainval,trainval表示train和val合在一起

Pascal Context

Pascal数据集介绍

PASCAL Context数据集[1]由两部分组成:

  1. PASCAL VOC 2010 语义分割数据集;
  2. Context 标注。

总共有459个类别,包含 10103 张图像,其中 4998 用于训练集,5105 用于验证集。

现在最广泛地用法是使用其中出现频率最高的 59 个类别最为语义标签,其余类别标记为背景即background。

#59个类别的数字索引
[ 0, 2, 259, 260, 415, 324, 9, 258, 144, 18, 19, 22, 
23, 397, 25, 284, 158, 159, 416, 33, 162, 420, 454, 295, 296, 
427, 44, 45, 46, 308, 59, 440, 445, 31, 232, 65, 354, 424, 
68, 326, 72, 458, 34, 207, 80, 355, 85, 347, 220, 349, 360, 
98, 187, 104, 105, 366, 189, 368, 113, 115]

PASCAL in Detail API

到此,原始图片和标注数据都已获取完毕,那么如何实现上述的 4998+5105 的训练/验证划分呢?

这里需要使用CVPR’17 PASCAL in Detail Challenge中实现的Detail接口。其github地址为:https://github.com/ccvl/detail-api

具体使用方法可以参考其提供的文档,这里不再赘述。

PASCAL VOC2012 Aug

ADE 20K

CityScape

cityscape数据集介绍
List of cityscapes labels:

                 name |  id | trainId |       category | categoryId | hasInstances | ignoreInEval|        color
--------------------------------------------------------------------------------------------------
            unlabeled |   0 |     255 |           void |          0 |            0 |            1 |         (0, 0, 0)
          ego vehicle |   1 |     255 |           void |          0 |            0 |            1 |         (0, 0, 0)
 rectification border |   2 |     255 |           void |          0 |            0 |            1 |         (0, 0, 0)
           out of roi |   3 |     255 |           void |          0 |            0 |            1 |         (0, 0, 0)
               static |   4 |     255 |           void |          0 |            0 |            1 |         (0, 0, 0)
              dynamic |   5 |     255 |           void |          0 |            0 |            1 |      (111, 74, 0)
               ground |   6 |     255 |           void |          0 |            0 |            1 |       (81, 0, 81)
                 road |   7 |       0 |           flat |          1 |            0 |            0 |    (128, 64, 128)
             sidewalk |   8 |       1 |           flat |          1 |            0 |            0 |    (244, 35, 232)
              parking |   9 |     255 |           flat |          1 |            0 |            1 |   (250, 170, 160)
           rail track |  10 |     255 |           flat |          1 |            0 |            1 |   (230, 150, 140)
             building |  11 |       2 |   construction |          2 |            0 |            0 |      (70, 70, 70)
                 wall |  12 |       3 |   construction |          2 |            0 |            0 |   (102, 102, 156)
                fence |  13 |       4 |   construction |          2 |            0 |            0 |   (190, 153, 153)
           guard rail |  14 |     255 |   construction |          2 |            0 |            1 |   (180, 165, 180)
               bridge |  15 |     255 |   construction |          2 |            0 |            1 |   (150, 100, 100)
               tunnel |  16 |     255 |   construction |          2 |            0 |            1 |    (150, 120, 90)
                 pole |  17 |       5 |         object |          3 |            0 |            0 |   (153, 153, 153)
            polegroup |  18 |     255 |         object |          3 |            0 |            1 |   (153, 153, 153)
        traffic light |  19 |       6 |         object |          3 |            0 |            0 |    (250, 170, 30)
         traffic sign |  20 |       7 |         object |          3 |            0 |            0 |     (220, 220, 0)
           vegetation |  21 |       8 |         nature |          4 |            0 |            0 |    (107, 142, 35)
              terrain |  22 |       9 |         nature |          4 |            0 |            0 |   (152, 251, 152)
                  sky |  23 |      10 |            sky |          5 |            0 |            0 |    (70, 130, 180)
               person |  24 |      11 |          human |          6 |            1 |            0 |     (220, 20, 60)
                rider |  25 |      12 |          human |          6 |            1 |            0 |       (255, 0, 0)
                  car |  26 |      13 |        vehicle |          7 |            1 |            0 |       (0, 0, 142)
                truck |  27 |      14 |        vehicle |          7 |            1 |            0 |        (0, 0, 70)
                  bus |  28 |      15 |        vehicle |          7 |            1 |            0 |      (0, 60, 100)
              caravan |  29 |     255 |        vehicle |          7 |            1 |            1 |        (0, 0, 90)
              trailer |  30 |     255 |        vehicle |          7 |            1 |            1 |       (0, 0, 110)
                train |  31 |      16 |        vehicle |          7 |            1 |            0 |      (0, 80, 100)
           motorcycle |  32 |      17 |        vehicle |          7 |            1 |            0 |       (0, 0, 230)
              bicycle |  33 |      18 |        vehicle |          7 |            1 |            0 |     (119, 11, 32)
        license plate |  -1 |      -1 |        vehicle |          7 |            0 |            1 |       (0, 0, 142)

Example usages:
ID of label ‘car’: 26
Category of label with ID ‘26’: vehicle
Name of label with trainID ‘0’: road

这张图片很重要,有些虽然有类别id,但是训练的时候trainId是255,不考虑,真正开始考虑的是road

COCO 2017

COCO数据集的介绍和使用

image-20211105170711982

pycocotools

from pycocotools.coco import COCO
print(dir(COCO))
# 下面是一些主要的方法
'annToMask', 'annToRLE', 'createIndex', 'download',
# 获取满足给定过滤条件的annid。
COCO.getAnnIds(self, imgIds=[],# get anns for given imgs
               catIds=[],# get anns for given cats
               areaRng=[],# get anns for given area range (e.g. [0 inf])
               iscrowd=None)# get anns for given crowd label (False or True)
'getCatIds', 'getImgIds',
# Print information about the annotation file.
COCO.info(self)
# 使用指定的id加载anns。
COCO.loadAnns(self, ids=[])
'loadCats', 'loadImgs', 'loadNumpyAnnotations', 'loadRes',
# 显示指定的annotations。
COCO.showAnns(self, anns)

pycocotools中的三个py文件

Run Length Code

RLE(Run- Length Encoding 行程长度编码)压缩算法是Windows 系统中使用的一种图像文件压缩方法, 其基本思想是: 将一扫描行中颜色值相同的相邻像素用两个字节来表示, 第一个字节是一个计数值, 用于指定像素重复的次数; 第二个字节是具体像素的值[2]。主要通过压缩除掉数据中的冗余字节或字节中的冗余位,从而达到减少文件所占空间的目的。例如, 有一表示颜色像素值的字符串RRRRRGGBBBBBB,用RLE压缩方法压缩后可用 5R2G6B 来代替,显然后者的串长度比前者的串长度小得多。译码时按照与编码时采用的相同规则进行, 还原后得到的数据与压缩前的数据完全相同。因此,RLE是无损压缩技术。

image-20211105230029786

竞赛中的run length code是(start,length)形式,前面的是图片id,每个id有好几条数据,每个数据的标签是cell_type,经过我自己的一番操作发现好像每张图片只有一种细胞类型!

def rle2mask(rle, img_w, img_h):

    array = np.fromiter(rle.split(), dtype = np.uint)
    array = array.reshape((-1,2)).T
    array[0] = array[0] - 1 # 每个点的位置都减1,可能是因为mask数组是从0开始
    starts, lenghts = array
    mask_decompressed = np.concatenate([np.arange(s, s + l, dtype = np.uint) for s, l in zip(starts, lenghts)])
    # 获得在一维数组的mask坐标
    msk_img = np.zeros(img_w * img_h, dtype = np.uint8)
    msk_img[mask_decompressed] = 1 # 所有的mask位置设成1,background设成0
    msk_img = msk_img.reshape((img_h, img_w))# resize成图片大小
    msk_img = np.asfortranarray(msk_img)
    return msk_img

SDD

Info

15年一个皮肤分割数据集<<A Skin Detection Dataset for Training and Assessment of Human Skin Classifiers>>

Abstract

超过20000张图像 非常精确:专业图形工具 三元划分 与SFA比较 定性且定量表明更好

Conclusion

数据库组织良好:因此使用时只和方法有关,而和数据集无关

不同光照和成像条件下捕获

不像许多其他数据集与半自动GT标签,在SDD,地面真相注释非常精确,感谢专业图形工具的使用和三元划分的想法。

使用后者,处理皮肤和非皮肤区域边界上的繁琐点会更加方便和容易。

对于该数据集的评价,由于单直方图方法的沉默特性,无论是定性还是定量都选择了单直方图方法,结果表明使用SDD方法比SFA更有效。

Introduction

Skin Classification

例如,有些数据库认为人类嘴唇是皮肤的一部分,而有些数据库则忽略了它。

目前数据库中的地面真值图像往往太不准确(本文将对此进行说明)。

事实上,数据集有时是手工注释的,但是,由于这项任务既无聊又费时,它可能被漫不经心地完成。

在其他数据库中,GT图像使用半自动程序生成,以减少注释时间。然而,ground truth图像还不够精确,甚至可能比人工标记的图像更差。

在一些数据库中,皮肤像素被标记为非皮肤像素,但它们甚至不靠近皮肤区域,在某些情况下,非皮肤像素被标记为皮肤像素,这在一定程度上降低了性能。

在一些数据库中,皮肤像素被标记为非皮肤像素,在某些情况下,非皮肤像素被标记为皮肤像素,这在一定程度上降低了性能。

此外,训练集和测试集的数量和多样性对分类器性能的影响也很明显。然而,在一些工作中,这一因素往往被忽略。有很多作品在报告统计结果时没有考虑到照片集的大小和多样性的影响。一些数据集是在特定的成像和照明条件下编译的。这在评估和培训步骤中都可能出现问题。在评估中,如果数据集不够一般化,算法的结果要么太好,要么太差,都是不现实的。在训练中,使用非通用数据库仅根据特定类型的皮肤像素对系统进行优化,会严重影响算法的性能。有些数据库太小,无法用于各种方法的培训。例如,考虑Jones et al.[17]开发的Bayesian方法,在一种情况下,无论皮肤直方图还是非皮肤直方图,LUT (look-up table)的大小都达到了2×2563个细胞。要对该算法进行适当的训练,需要一个比可能的单元格整个大小大几倍的数据集。在某些情况下,即使数据库相对较大,其大多数映像也会重复多次。此外,一些数据集既不能用于公共用途,也不能免费用于非商业学术用途。基于上述问题,本文的目标是编制一个半理想的应用数据集,可用于训练和评估皮肤检测方法

Previous Databases

一些皮肤检测数据集最初是为人脸检测、手跟踪和人脸识别问题而开发的。最重要的皮肤数据库组是那些专门为皮肤分类器的训练和评估而设计的,而不是其他生物识别应用。

康柏是一个相对较老的数据库,其图像质量太低,不再值得信赖。新一代的成像设备已经被开发出来并用于商业用途,它们与以前的设备有很大的不同。另一个问题是康柏没有明确的划分,即不同的作者在测试和评估过程中可能使用不同的图像,这将影响性能。半监督标注,非常不准确

ECU图像保证了背景场景、光照条件和皮肤类型的多样性。照明条件包括室内照明和室外照明;皮肤类型包括白色,棕色,黄色和黑色皮肤。一些作品已经用这个数据库进行了评估。虽然图像的多样性足以用于评估一般的皮肤检测系统,但数据集的大小还不够大。此外,处理注释还存在一个特殊的问题,即所有图像中,特别是那些质量较低或拥挤的图像中的某些区域,注释并不是一项简单的任务。例如,图3中红色箭头表示的点是毛发周围的像素点,或者其他物体往往会带来额外的困难。这实际上是GTs手工标记方案的错误来源

基于神经网络皮肤分类器的最佳拓扑和阈值,将UCI和SFA进行了比较,发现在评估皮肤检测器[35]时,SFA的准确性略高于UCI。然而,SFA主要包括半护照图像,不适合用于评估目的。另外,SFA中的GT注释也不一致,即有很多图像没有进行准确的标注。此外,在一些图像中,人脸被2-3像素的厚白色边界包围。这将导致不同颜色空间皮肤簇的构建不准确。图4绘制了GTs对应的SFA图像;它们代表了所有的图像。这个数据集是公开的。

SDD

据作者所知,它是文献中引入的用于训练和评估皮肤分类器性能的最大数据库。图像是在不同的光照条件下拍摄的,使用不同的成像设备,从世界各地不同肤色的人。一些图像是在线视频和电影的快照,而一些是从流行的人脸识别/跟踪/检测数据集中获取的静态图像[40-43]。SDD中图像的高度多样性使得它可以用于一般系统的训练和评估,即当一种方法被SDD评估时,结果是可靠的,而当一种方法被SDD训练时,它可以达到其最大的潜在性能。

如前所述,所有图片中有一些像素要么skinness的有一个问题(比如眉毛和眼睛周围地区,嘴唇和鼻子孔,等等)或者是位于皮肤和non-skin的边界,在这两种情况下,很难区分skinness和一些图片,要花很多的时间来注释。将GT图像划分为3个不重叠区域;皮肤像素、非皮肤像素以及在评估和训练步骤中都被考虑的像素(不关心点)

用的Photoshop CS5

$$
F1=\frac{2\cdot Recall\cdot Precision}{Recall+Precision}
$$

$$
IoU=\frac{tp}{tp+fn+fp}
$$


文章作者: Dch
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Dch !
评论
  目录