当前位置:   article > 正文

Person Re-Identification(ReID行人重识别)_flowchart pf person re-identification

flowchart pf person re-identification

在这里插入图片描述

ReID?
ReID是图像检索的子任务,它主要的目的是:利用计算机视觉技术对特定行人进行跨视域匹配和检索。所谓跨视域即是图片来自于不同的摄像头,这样可以用于智能视频监控(如无人超市)、刑侦(追捕嫌疑人)、交管(追踪车辆等)等等应用场景。如上图,需要检索到同一个人(查询图像query)在各个摄像头下图片集(候选行人库gallery)的相关图片。

在这里插入图片描述

困难点
困难点主要在于ReID任务的跨视域特性有:

  • 摄像头分辨率不同
  • 拍摄角度不一 致
  • 光照条件不同
  • 背景变化大
  • 人体属于非刚性目标,外观会因姿态、遮挡、光照、背景、行人错位等等的干扰,如上图
  • 行人数据集采集标注困难

ReID的实现流程图
时间中需要完成包括行人检测和再识别两部分任务,即下图的person detection和后面的person reID,研究上主要侧重于识别的部分(查询图像query集和候选行人库gallery集都是经过detector裁剪好的行人框)。

识别部分分为feature extraction和similarity measurement,即特征提取和相似度度量。

  • 特征提取:学习在不同摄像头下图片中的行人特征
  • 相似度度量 :比较特征以排序检索
    在这里插入图片描述

依据流程,数据集实际分为了训练集、验证集、Query、Gallery四个部分。即在训练集上进行模型的训练,得到模型后对Query与Gallery中的图片提取特征计算相似度,对于每个Query在Gallery中找出前N个与其相似的图片。

├── Market/
│   ├── bounding_box_test/          /* Files for testing (candidate images pool)19732张
│   ├── bounding_box_train/         /* Files for training,12936张
│   ├── gt_bbox/                    /* Files for multiple query testing,3368张,对应query,在评估时使用
│   ├── gt_query/                   /* We do not use it 
│   ├── query/                      /* Files for testing (query images)3368张查询,会到test中寻找
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

数据集实例如上,值得注意的是训练集的人和测试集的人没有重复的。比如market里面有751名个人用于训练,另外有750个人用于测试。

如果Gallery中没有Query怎么办?
这种情况实际中很可能会存在,但或许ReID的目的不是为了精确的找到Query,而是返回一个候选列表帮助人工筛选,这样不存在也可能很快发现。

single shot 和muti shot
single shot是指gallery中每个人的图像为一张(N=1),而muti shot是指gallery中每个人的图像为N>1张图像,同样的Rank-1下,一般N越大,得到的识别率越高。

query = qf.view(-1,1)
# print(query.shape)
score = torch.mm(gf,query) # Cosine Distance
score = score.squeeze(1).cpu()
score = score.numpy()
# predict index
index = np.argsort(score)  #from small to large
index = index[::-1]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

主要流行的解决方法
主要有三种,基于表征,加入局部信息,引入生成对抗。

  • 基于预测。即两张图片输入网络,预测其“相同”或者“不同”。
  • 基于分类。即一张图片输入网络,分类映射其该图片的任务ID。
  • 基于三元组。即给出正例负例图片对,重点拉开不同类图片之间的差距。
  • 基于局部身体部件。提取局部特征增大信息量,还可以解决部分遮挡问题。
  • 基于水平分块。分块后可以对齐局部以减缓分辨率问题和局部的不稳定。
  • 基于注意力机制。这种方法是加强局部信息的终极版,自行关注重要区域,还可以引导学习区域性信息。
  • 基于行人姿态生成。输入图片得到行人姿态,引入姿态信息加强。
  • 基于图像风格转换。主要解决各个场景的风格不一致问题,使用GAN来跨域迁移风格生成,用于数据增广是很好的。

来自中文综述论文

卢健,陈旭,罗毛欣,王航英. 深度学习行人再识别研究综述. 
  • 1

实际上应该还有很多其他的方法,比如人体属性,骨架Graph等等,还有涉及无监督和跨模态的任务等等。

在这里插入图片描述
Trick合集
fastreid是一个集成了超级多实现的开源代码:https://github.com/JDAI-CV/fast-reid

  • pre-processing:有改变大小,翻转,随机擦除补0替换等等的对图片的预处理操作,以增强图片的鲁棒性。
  • backbone:基础的提取特征单元,也实现了流行的resnet,resnest,resnext等等,即插即用。
  • aggregation:聚合特征,其中gem是介于avg和max的一种方法
  • head:用于做特征规约,减少参数数量
  • loss:除了一般的交叉熵,三元组loss,还实现了arcloss和circleloss等比较新的函数
  • 训练阶段其他trick:学习率递减,网络参数热身,便于fine-turn网络等等的代码
  • distance metric:将得到的特征进行比对,实现了普通的欧几里德,余弦,还有对于size不一样的情况的DSR算法
  • post-processing:主要是两个trick,一是rerank,即把检索出来的图片也再检索一次,如果被检索图片也能检索到原query,则rank靠前。二是查询扩大,即用所有的检索结果的均值再检索一遍。这两种都是对rank性能的后处理。
  • evaluation:对reid性能的评价,如CMC和ROC等等。
    这个开源代码做的很工程,任何部分都是可拆卸,可拼装的,非常方便。

当前一些sota方法的实现与表现
多蹲蹲顶会和开源就好…

  • code:https://github.com/layumi/Person_reID_baseline_pytorch/tree/master/leaderboard
  • 视频:https://www.bilibili.com/video/BV1Mx411871F
  • 超全随笔:https://www.cnblogs.com/orangecyh/category/1570883.html
  • 知乎讨论:https://www.zhihu.com/question/46943328
  • 论文泛读:https://blog.csdn.net/u013982164/article/details/79608100
  • https://blog.csdn.net/weixin_41427758/article/details/81187997

简单注释一下基模型的代码:

class ClassBlock(nn.Module):
    def __init__(self, input_dim, class_num, droprate, relu=False, bnorm=True, num_bottleneck=512, linear=True, return_f = False):
        super(ClassBlock, self).__init__()
        self.return_f = return_f
        add_block = [] #图像特征抽象
        if linear: #多个mlp
            add_block += [nn.Linear(input_dim, num_bottleneck)]
        else:
            num_bottleneck = input_dim
        if bnorm: #bn层
            add_block += [nn.BatchNorm1d(num_bottleneck)]
        if relu: #激活函数
            add_block += [nn.LeakyReLU(0.1)]
        if droprate>0: #dropout
            add_block += [nn.Dropout(p=droprate)]
        add_block = nn.Sequential(*add_block) #把多个mlp串起来
        add_block.apply(weights_init_kaiming) #然后应用kaiming初始化

        classifier = [] #分类器网络
        classifier += [nn.Linear(num_bottleneck, class_num)] #也是mlp得到分类ID数目
        classifier = nn.Sequential(*classifier)
        classifier.apply(weights_init_classifier)

        self.add_block = add_block #特征抽取
        self.classifier = classifier #映射到ID
    def forward(self, x):
        x = self.add_block(x) #先得到特征
        if self.return_f: #再分类
            f = x
            x = self.classifier(x)
            return x,f
        else:
            x = self.classifier(x)
            return x
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

这个基方案可以搭得更深就是了如 AlexNet, VGG16, ResNet and DenseNet等等,还想注释一下PCB。
在这里插入图片描述
PCB(Part-Based Convolutional Baseline)将行人图片均匀划分为6个部件并提取特征,用6个分类的损失函数进行模型训练。这么做的意义是能够基于行人结构分割的先验知识驱使,比如part1就是行人的头部。

class PCB(nn.Module):
    def __init__(self, class_num ):
        super(PCB, self).__init__()

        self.part = 6 # 切成6份
        model_ft = models.resnet50(pretrained=True)#用resnet50提特征
        self.model = model_ft
        self.avgpool = nn.AdaptiveAvgPool2d((self.part,1))
        self.dropout = nn.Dropout(p=0.5)
        # remove the final downsample
        self.model.layer4[0].downsample[0].stride = (1,1)
        self.model.layer4[0].conv2.stride = (1,1)
        # 定义6分类
        for i in range(self.part):
            name = 'classifier'+str(i)
            setattr(self, name, ClassBlock(2048, class_num, droprate=0.5, relu=False, bnorm=True, num_bottleneck=256))

    def forward(self, x): #逐层前向就行
        x = self.model.conv1(x)
        x = self.model.bn1(x)
        x = self.model.relu(x)
        x = self.model.maxpool(x)
        
        x = self.model.layer1(x)
        x = self.model.layer2(x)
        x = self.model.layer3(x)
        x = self.model.layer4(x)
        x = self.avgpool(x)
        x = self.dropout(x)
        part = {}
        predict = {}
        # 6个部分的特征 batchsize*2048*6
        for i in range(self.part):
            part[i] = torch.squeeze(x[:,:,i])
            name = 'classifier'+str(i)
            c = getattr(self,name)
            predict[i] = c(part[i])

        # sum prediction
        #y = predict[0]
        #for i in range(self.part-1):
        #    y += predict[i+1]
        y = []
        for i in range(self.part):
            y.append(predict[i])
        return y
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

当然还有一些更复杂的模型咯,更多的论文都可以参考上面的那个开源。

数据集
现有的数据集都不是很大,ID和摄像头都不是很多。
在这里插入图片描述

评价指标
一般使用rank-n,即搜索结果中最靠前(置信度分数最高)的n张图有正确结果的概率。
例如: lable ID为行人0001,在100个样本中搜索。

  • 如果识别结果是0001、0051、0013、0004、0015……,则此时rank-1的正确率为100%;rank-2的正确率也为100%;rank-5的正确率也为100%;
  • 如果识别结果是0051、0001、0013、0004、0015……,则此时rank-1的正确率为0%;rank-2的正确率为100%;rank-5的正确率也为100%;

在这里插入图片描述

怎么真实应用?
真实场景中的情况,和公共数据集的数据是不一样的,往往是需要从原视频/图像的一整张大图中,先做检测找出小人,然后才在所建立的gallery里面进行查询和检索的。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/595516
推荐阅读
相关标签
  

闽ICP备14008679号