【mmpose】从openmmlab官方文档看mmpose架构设计,模块组成,快速上手实现关键点检测效果(动物,人体,手部等)

news2024/11/28 7:44:31

MMPOSE 架构设计

  • MMPose 1.0 与之前的版本有较大改动,对部分模块进行了重新设计和组织,降低代码冗余度,提升运行效率,降低学习难度。使用 MMPose 1.0 时开发者会关心的内容:

    • 整体代码架构与设计逻辑;

    • 如何用config文件管理模块;

    • 如何使用自定义数据集;

    • 如何添加新的模块(骨干网络、模型头部、损失函数等)。

  • 总体设计

    • 在这里插入图片描述

    • 一般来说,开发者在项目开发过程中经常接触内容的主要有五个方面:

      • 通用:环境、钩子(Hook)、模型权重存取(Checkpoint)、日志(Logger)等;

      • 数据:数据集、数据读取(Dataloader)、数据增强等;

      • 训练:优化器、学习率调整等;

      • 模型:主干网络、颈部模块(Neck)、预测头模块(Head)、损失函数等;

      • 评测:评测指标(Metric)、评测器(Evaluator)等。

    • 其中通用训练评测相关的模块往往由训练框架提供,开发者只需要调用和调整参数,不需要自行实现,开发者主要实现的是数据模型部分

    配置文件

    • 在MMPose中,通常 python 格式的配置文件配置文件 — MMPose 1.0.0 文档,用于整个项目的定义、参数管理,因此强烈建议第一次接触 MMPose 的开发者,学习配置文件的定义。

    • 需要注意的是,所有新增的模块都需要使用注册器(Registry)进行注册,并在对应目录的 __init__.py 中进行 import,以便能够使用配置文件构建其实例

    • 快速实现推理效果:使用现有模型进行推理 — MMPose 1.0.0 文档

    数据

    • MMPose 数据的组织主要包含三个方面:数据集元信息;数据集;数据流水线

    • 元信息指具体标注之外的数据集信息。姿态估计数据集的元信息通常包括:关键点和骨骼连接的定义、对称性、关键点性质(如关键点权重、标注标准差、所属上下半身)等。这些信息在数据在数据处理、模型训练和测试中有重要作用。在 MMPose 中,数据集的元信息使用 python 格式的配置文件保存,位于 $MMPOSE/configs/_base_/datasets 目录下。

    • 在 MMPose 中使用自定义数据集时,你需要增加对应的元信息配置文件。以 MPII 数据集($MMPOSE/configs/_base_/datasets/mpii.py)为例:

      • dataset_info = dict(
            dataset_name='mpii',
            paper_info=dict(
                author='Mykhaylo Andriluka and Leonid Pishchulin and '
                'Peter Gehler and Schiele, Bernt',
                title='2D Human Pose Estimation: New Benchmark and '
                'State of the Art Analysis',
                container='IEEE Conference on Computer Vision and '
                'Pattern Recognition (CVPR)',
                year='2014',
                homepage='http://human-pose.mpi-inf.mpg.de/',
            ),
            keypoint_info={
                0:
                dict(
                    name='right_ankle',
                    id=0,
                    color=[255, 128, 0],
                    type='lower',
                    swap='left_ankle'),
                ## 内容省略
            },
            skeleton_info={
                0:
                dict(link=('right_ankle', 'right_knee'), id=0, color=[255, 128, 0]),
                ## 内容省略
            },
            joint_weights=[
                1.5, 1.2, 1., 1., 1.2, 1.5, 1., 1., 1., 1., 1.5, 1.2, 1., 1., 1.2, 1.5
            ],
            # 使用 COCO 数据集中提供的 sigmas 值
            sigmas=[
                0.089, 0.083, 0.107, 0.107, 0.083, 0.089, 0.026, 0.026, 0.026, 0.026,
                0.062, 0.072, 0.179, 0.179, 0.072, 0.062
            ])
        
    • 在模型配置文件中,你需要为自定义数据集指定对应的元信息配置文件。假如该元信息配置文件路径为 $MMPOSE/configs/_base_/datasets/custom.py,指定方式如下:

      • # dataset and dataloader settings
        dataset_type = 'MyCustomDataset' # or 'CocoDataset'
        train_dataloader = dict(
            batch_size=2,
            dataset=dict(
                type=dataset_type,
                data_root='root/of/your/train/data',
                ann_file='path/to/your/train/json',
                data_prefix=dict(img='path/to/your/train/img'),
                # 指定对应的元信息配置文件
                metainfo=dict(from_file='configs/_base_/datasets/custom.py'),
                ...),
            )
        val_dataloader = dict(
            batch_size=2,
            dataset=dict(
                type=dataset_type,
                data_root='root/of/your/val/data',
                ann_file='path/to/your/val/json',
                data_prefix=dict(img='path/to/your/val/img'),
                # 指定对应的元信息配置文件
                metainfo=dict(from_file='configs/_base_/datasets/custom.py'),
                ...),
            )
        test_dataloader = val_dataloader
        
    • 数据集

      • 在 MMPose 中使用自定义数据集时,官方推荐将数据转化为已支持的格式(如 COCO 或 MPII),并直接使用官方提供的对应数据集实现。如果这种方式不可行,则用户需要实现自己的数据集类。MMPose 中的大部分 2D 关键点数据集以 COCO 形式组织2D Body Keypoint Datasets — MMPose 1.0.0 文档,为此官方提供了基类 BaseCocoStyleDataset。推荐用户继承该基类,并按需重写它的方法(通常是 __init__() 和 _load_annotations() 方法),以扩展到新的 2D 关键点数据集

      • 下面我们以MPII数据集的实现($MMPOSE/mmpose/datasets/datasets/body/mpii_dataset.py)为例:

      • @DATASETS.register_module()
        class MpiiDataset(BaseCocoStyleDataset):
            METAINFO: dict = dict(from_file='configs/_base_/datasets/mpii.py')
            def __init__(self,
                         ## 内容省略
                         headbox_file: Optional[str] = None,
                         ## 内容省略):
                if headbox_file:
                    if data_mode != 'topdown':
                        raise ValueError(
                            f'{self.__class__.__name__} is set to {data_mode}: '
                            'mode, while "headbox_file" is only '
                            'supported in topdown mode.')
                    if not test_mode:
                        raise ValueError(
                            f'{self.__class__.__name__} has `test_mode==False` '
                            'while "headbox_file" is only '
                            'supported when `test_mode==True`.')
                    headbox_file_type = headbox_file[-3:]
                    allow_headbox_file_type = ['mat']
                    if headbox_file_type not in allow_headbox_file_type:
                        raise KeyError(
                            f'The head boxes file type {headbox_file_type} is not '
                            f'supported. Should be `mat` but got {headbox_file_type}.')
                self.headbox_file = headbox_file
                super().__init__(
                    ## 内容省略
                    )
            def _load_annotations(self) -> List[dict]:
                """Load data from annotations in MPII format."""
                check_file_exist(self.ann_file)
                with open(self.ann_file) as anno_file:
                    anns = json.load(anno_file)
                if self.headbox_file:
                    check_file_exist(self.headbox_file)
                    headbox_dict = loadmat(self.headbox_file)
                    headboxes_src = np.transpose(headbox_dict['headboxes_src'],
                                                 [2, 0, 1])
                    SC_BIAS = 0.6
                data_list = []
                ann_id = 0
                # mpii bbox scales are normalized with factor 200.
                pixel_std = 200.
                for idx, ann in enumerate(anns):
                    center = np.array(ann['center'], dtype=np.float32)
                    scale = np.array([ann['scale'], ann['scale']],
                                     dtype=np.float32) * pixel_std
                    # Adjust center/scale slightly to avoid cropping limbs
                    if center[0] != -1:
                        center[1] = center[1] + 15. / pixel_std * scale[1]
                    # MPII uses matlab format, index is 1-based,
                    # we should first convert to 0-based index
                    center = center - 1
                    # unify shape with coco datasets
                    center = center.reshape(1, -1)
                    scale = scale.reshape(1, -1)
                    bbox = bbox_cs2xyxy(center, scale)
                    # load keypoints in shape [1, K, 2] and keypoints_visible in [1, K]
                    keypoints = np.array(ann['joints']).reshape(1, -1, 2)
                    keypoints_visible = np.array(ann['joints_vis']).reshape(1, -1)
                    data_info = {
                        'id': ann_id,
                        'img_id': int(ann['image'].split('.')[0]),
                        'img_path': osp.join(self.data_prefix['img'], ann['image']),
                        'bbox_center': center,
                        'bbox_scale': scale,
                        'bbox': bbox,
                        'bbox_score': np.ones(1, dtype=np.float32),
                        'keypoints': keypoints,
                        'keypoints_visible': keypoints_visible,
                    }
                    if self.headbox_file:
                        # calculate the diagonal length of head box as norm_factor
                        headbox = headboxes_src[idx]
                        head_size = np.linalg.norm(headbox[1] - headbox[0], axis=0)
                        head_size *= SC_BIAS
                        data_info['head_size'] = head_size.reshape(1, -1)
                    data_list.append(data_info)
                    ann_id = ann_id + 1
                return data_list
        
      • 在对MPII数据集进行支持时,由于MPII需要读入 head_size 信息来计算 PCKh,因此我们在__init__()中增加了 headbox_file,并重载了 _load_annotations() 来完成数据组织。如果自定义数据集无法被 BaseCocoStyleDataset 支持,你需要直接继承 MMEngine 中提供的 BaseDataset 基类。数据集基类(BaseDataset) — mmengine 0.7.4 文档

    • 数据流水线

      • 一个典型的数据流水线配置如下:

        • # pipelines
          train_pipeline = [
              dict(type='LoadImage'),
              dict(type='GetBBoxCenterScale'),
              dict(type='RandomFlip', direction='horizontal'),
              dict(type='RandomHalfBody'),
              dict(type='RandomBBoxTransform'),
              dict(type='TopdownAffine', input_size=codec['input_size']),
              dict(type='GenerateTarget', encoder=codec),
              dict(type='PackPoseInputs')
          ]
          test_pipeline = [
              dict(type='LoadImage'),
              dict(type='GetBBoxCenterScale'),
              dict(type='TopdownAffine', input_size=codec['input_size']),
              dict(type='PackPoseInputs')
          ]
          
      • 在关键点检测任务中,数据一般会在三个尺度空间中变换:

        • 原始图片空间:图片存储时的原始空间,不同图片的尺寸不一定相同;

        • 输入图片空间:模型输入的图片尺度空间,所有图片和标注被缩放到输入尺度,如 256x256,256x192 等;

        • 输出尺度空间:模型输出和训练监督信息所在的尺度空间,如64x64(热力图),1x1(回归坐标值)等。

      • 数据在三个空间中变换的流程如图所示:

        • 在这里插入图片描述
    • 数据增强

      • 数据增强中常用的变换存放在 $MMPOSE/mmpose/datasets/transforms/common_transforms.py 中,如 RandomFlipRandomHalfBody 等。

      • 对于 top-down 方法,ShiftRotateResize 操作由 RandomBBoxTransform来实现;对于 bottom-up 方法,这些则是由 BottomupRandomAffine 实现

    • 数据变换

      • 我们使用仿射变换,将图像和坐标标注从原始图片空间变换到输入图片空间。这一操作在 top-down 方法中由 TopdownAffine 完成,在 bottom-up 方法中则由 BottomupRandomAffine 完成。
    • 数据编码

      • 在模型训练时,数据从原始空间变换到输入图片空间后,需要使用 GenerateTarget 来生成训练所需的监督目标(比如用坐标值生成高斯热图),我们将这一过程称为编码(Encode),反之,通过高斯热图得到对应坐标值的过程称为解码(Decode)。在 MMPose 中,我们将编码和解码过程集合成一个编解码器(Codec),在其中实现 encode()decode()

      • 值得注意的是,我们对 top-down 和 bottom-up 的数据格式进行了统一,这意味着标注信息中会新增一个维度来代表同一张图里的不同目标(如人),格式为:

      • [batch_size, num_instances, num_keypoints, dim_coordinates] 
        top-down:[B, 1, K, D]  
        Bottom-up: [B, N, K, D]
        
      • 当前已经支持的编解码器定义在 $MMPOSE/mmpose/codecs 目录下,如果你需要自定新的编解码器,可以前往编解码器了解更多详情。

    • 数据打包

      • 数据经过前处理变换后,最终需要通过 PackPoseInputs 打包成数据样本。该操作定义在 $MMPOSE/mmpose/datasets/transforms/formatting.py 中。

      • 打包过程会将数据流水线中用字典 results 存储的数据转换成用 MMPose 所需的标准数据结构, 如 InstanceDataPixelDataPoseDataSample 等。

      • 具体而言,我们将数据样本内容分为 gt(标注真值) 和 pred(模型预测)两部分,它们都包含以下数据项:

        • instances(numpy.array):实例级别的原始标注或预测结果,属于原始尺度空间;

        • instance_labels(torch.tensor):实例级别的训练标签(如归一化的坐标值、关键点可见性),属于输出尺度空间;

        • fields(torch.tensor):像素级别的训练标签(如高斯热图)或预测结果,属于输出尺度空间。

      • 下面是 PoseDataSample 底层实现的例子:

        • def get_pose_data_sample(self):
              # meta
              pose_meta = dict(
                  img_shape=(600, 900),  # [h, w, c]
                  crop_size=(256, 192),  # [h, w]
                  heatmap_size=(64, 48),  # [h, w]
              )
              # gt_instances
              gt_instances = InstanceData()
              gt_instances.bboxes = np.random.rand(1, 4)
              gt_instances.keypoints = np.random.rand(1, 17, 2)
              # gt_instance_labels
              gt_instance_labels = InstanceData()
              gt_instance_labels.keypoint_labels = torch.rand(1, 17, 2)
              gt_instance_labels.keypoint_weights = torch.rand(1, 17)
              # pred_instances
              pred_instances = InstanceData()
              pred_instances.keypoints = np.random.rand(1, 17, 2)
              pred_instances.keypoint_scores = np.random.rand(1, 17)
              # gt_fields
              gt_fields = PixelData()
              gt_fields.heatmaps = torch.rand(17, 64, 48)
              # pred_fields
              pred_fields = PixelData()
              pred_fields.heatmaps = torch.rand(17, 64, 48)
              data_sample = PoseDataSample(
                  gt_instances=gt_instances,
                  pred_instances=pred_instances,
                  gt_fields=gt_fields,
                  pred_fields=pred_fields,
                  metainfo=pose_meta)
              return data_sample
          

模型

  • 模型组成部分:

    • 预处理器(DataPreprocessor):完成图像归一化和通道转换等前处理;

    • 主干网络 (Backbone):用于特征提取;

    • 颈部模块(Neck):GAP,FPN 等可选项;

    • 预测头(Head):用于实现核心算法功能和损失函数定义。

  • $MMPOSE/models/pose_estimators/base.py 下为姿态估计模型定义了一个基类 BasePoseEstimator,所有的模型(如 TopdownPoseEstimator)都需要继承这个基类,并重载对应的方法。

  • 在模型的 forward() 方法中提供了三种不同的模式:

    • mode == 'loss':返回损失函数计算的结果,用于模型训练;

    • mode == 'predict':返回输入尺度下的预测结果,用于模型推理;

    • mode == 'tensor':返回输出尺度下的模型输出,即只进行模型前向传播,用于模型导出.

  • 开发者需要在 PoseEstimator 中按照模型结构调用对应的 Registry ,对模块进行实例化。以 top-down 模型为例:

    • @MODELS.register_module()
      class TopdownPoseEstimator(BasePoseEstimator):
          def __init__(self,
                       backbone: ConfigType,
                       neck: OptConfigType = None,
                       head: OptConfigType = None,
                       train_cfg: OptConfigType = None,
                       test_cfg: OptConfigType = None,
                       data_preprocessor: OptConfigType = None,
                       init_cfg: OptMultiConfig = None):
              super().__init__(data_preprocessor, init_cfg)
              self.backbone = MODELS.build(backbone)
              if neck is not None:
                  self.neck = MODELS.build(neck)
              if head is not None:
                  self.head = MODELS.build(head)
      
  • 前处理器(DataPreprocessor)

    • 从 MMPose 1.0 开始,在模型中添加了新的前处理器模块,用以完成图像归一化、通道顺序变换等操作。这样做的好处是可以利用 GPU 等设备的计算能力加快计算,并使模型在导出和部署时更具完整性。在配置文件中,一个常见的 data_preprocessor 如下:

    • data_preprocessor=dict(
              type='PoseDataPreprocessor',
              mean=[123.675, 116.28, 103.53],
              std=[58.395, 57.12, 57.375],
              bgr_to_rgb=True),
      
    • 它会将输入图片的通道顺序从 bgr 转换为 rgb,并根据 meanstd 进行数据归一化

  • 主干网络(Backbone)

    • MMPose 实现的主干网络存放在 $MMPOSE/mmpose/models/backbones 目录下。在实际开发中,开发者经常会使用预训练的网络权重进行迁移学习,这能有效提升模型在小数据集上的性能。 在 MMPose 中,只需要在配置文件 backboneinit_cfg 中设置:

    • init_cfg=dict(
          type='Pretrained',
          checkpoint='PATH/TO/YOUR_MODEL_WEIGHTS.pth'),
      
    • 如果你想只加载一个训练好的 checkpoint 的 backbone 部分,你需要指明一下前缀 prefix:

    • init_cfg=dict(
          type='Pretrained',
          prefix='backbone.',
          checkpoint='PATH/TO/YOUR_CHECKPOINT.pth'),
      
    • 其中 checkpoint 既可以是本地路径,也可以是下载链接。因此,如果你想使用 Torchvision 提供的预训练模型(比如ResNet50),可以使用:

    • init_cfg=dict(
          type='Pretrained',
          checkpoint='torchvision://resnet50')
      
    • 除了这些常用的主干网络以外,你还可以从 MMClassification 等其他 OpenMMLab 项目中方便地迁移主干网络,它们都遵循同一套配置文件格式,并提供了预训练权重可供使用。需要强调的是,如果你加入了新的主干网络,需要在模型定义时进行注册。同时在 $MMPOSE/mmpose/models/backbones/__init__.py 下进行 import,并加入到 __all__ 中,才能被配置文件正确地调用。

  • 颈部模块(Neck)

    • 颈部模块通常是介于主干网络和预测头之间的模块,在部分模型算法中会用到,常见的颈部模块有:

      • Global Average Pooling (GAP)

      • Feature Pyramid Networks (FPN)

      • Feature Map Processor (FMP)

        • FeatureMapProcessor 是一个通用的 PyTorch 模块,旨在通过选择、拼接和缩放等非参数变换将主干网络输出的特征图转换成适合预测头的格式。以下是一些操作的配置方式及效果示意图:

        • 选择操作 neck=dict(type='FeatureMapProcessor', select_index=0)

        • 在这里插入图片描述

        • 拼接操作 neck=dict(type='FeatureMapProcessor', concat=True),拼接之前,其它特征图会被缩放到和序号为 0 的特征图相同的尺寸。

        • 在这里插入图片描述

        • 缩放操作 neck=dict(type='FeatureMapProcessor', scale_factor=2.0).

        • 在这里插入图片描述

  • 预测头(Head)

    • 通常来说,预测头是模型算法实现的核心,用于控制模型的输出,并进行损失函数计算。MMPose 中 Head 相关的模块定义在 $MMPOSE/mmpose/models/heads 目录下,开发者在自定义预测头时需要继承我们提供的基类 BaseHead并重载以下三个方法对应模型推理的三种模式:forward();predict();loss()

    • 具体而言,predict() 返回的应是输入图片尺度下的结果,因此需要调用 self.decode() 对网络输出进行解码,这一过程实现在 BaseHead 中已经实现,它会调用编解码器提供的 decode() 方法来完成解码。另一方面,我们会在 predict() 中进行测试时增强。在进行预测时,一个常见的测试时增强技巧是进行翻转集成。即,将一张图片先进行一次推理,再将图片水平翻转进行一次推理,推理的结果再次水平翻转回去,对两次推理的结果进行平均。这个技巧能有效提升模型的预测稳定性。下面是在 RegressionHead 中定义 predict() 的例子:

    • def predict(self,
                  feats: Tuple[Tensor],
                  batch_data_samples: OptSampleList,
                  test_cfg: ConfigType = {}) -> Predictions:
          """Predict results from outputs."""
          if test_cfg.get('flip_test', False):
              # TTA: flip test -> feats = [orig, flipped]
              assert isinstance(feats, list) and len(feats) == 2
              flip_indices = batch_data_samples[0].metainfo['flip_indices']
              input_size = batch_data_samples[0].metainfo['input_size']
              _feats, _feats_flip = feats
              _batch_coords = self.forward(_feats)
              _batch_coords_flip = flip_coordinates(
                  self.forward(_feats_flip),
                  flip_indices=flip_indices,
                  shift_coords=test_cfg.get('shift_coords', True),
                  input_size=input_size)
              batch_coords = (_batch_coords + _batch_coords_flip) * 0.5
          else:
              batch_coords = self.forward(feats)  # (B, K, D)
          batch_coords.unsqueeze_(dim=1)  # (B, N, K, D)
          preds = self.decode(batch_coords)
      
    • loss()除了进行损失函数的计算,还会进行 accuracy 等训练时指标的计算,并通过一个字典 losses 来传递:

    •  # calculate accuracy
      _, avg_acc, _ = keypoint_pck_accuracy(
          pred=to_numpy(pred_coords),
          gt=to_numpy(keypoint_labels),
          mask=to_numpy(keypoint_weights) > 0,
          thr=0.05,
          norm_factor=np.ones((pred_coords.size(0), 2), dtype=np.float32))
      acc_pose = torch.tensor(avg_acc, device=keypoint_labels.device)
      losses.update(acc_pose=acc_pose)
      
    • 每个 batch 的数据都打包成了 batch_data_samples。以 Regression-based 方法为例,训练所需的归一化的坐标值和关键点权重可以用如下方式获取:

    • keypoint_labels = torch.cat(
          [d.gt_instance_labels.keypoint_labels for d in batch_data_samples])
      keypoint_weights = torch.cat([
          d.gt_instance_labels.keypoint_weights for d in batch_data_samples
      ])
      
    • 以下为 RegressionHead 中完整的 loss() 实现:

    • def loss(self,
               inputs: Tuple[Tensor],
               batch_data_samples: OptSampleList,
               train_cfg: ConfigType = {}) -> dict:
          """Calculate losses from a batch of inputs and data samples."""
          pred_outputs = self.forward(inputs)
          keypoint_labels = torch.cat(
              [d.gt_instance_labels.keypoint_labels for d in batch_data_samples])
          keypoint_weights = torch.cat([
              d.gt_instance_labels.keypoint_weights for d in batch_data_samples
          ])
          # calculate losses
          losses = dict()
          loss = self.loss_module(pred_outputs, keypoint_labels,
                                  keypoint_weights.unsqueeze(-1))
          if isinstance(loss, dict):
              losses.update(loss)
          else:
              losses.update(loss_kpt=loss)
          # calculate accuracy
          _, avg_acc, _ = keypoint_pck_accuracy(
              pred=to_numpy(pred_outputs),
              gt=to_numpy(keypoint_labels),
              mask=to_numpy(keypoint_weights) > 0,
              thr=0.05,
              norm_factor=np.ones((pred_outputs.size(0), 2), dtype=np.float32))
          acc_pose = torch.tensor(avg_acc, device=keypoint_labels.device)
          losses.update(acc_pose=acc_pose)
          return losses
      
  • 2D 动物图片姿态识别推理

    • python demo/topdown_demo_with_mmdet.py \
          ${MMDET_CONFIG_FILE} ${MMDET_CHECKPOINT_FILE} \
          ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \
          --input ${INPUT_PATH} --det-cat-id ${DET_CAT_ID} \
          [--show] [--output-root ${OUTPUT_DIR}] [--save-predictions] \
          [--draw-heatmap ${DRAW_HEATMAP}] [--radius ${KPT_RADIUS}] \
          [--kpt-thr ${KPT_SCORE_THR}] [--bbox-thr ${BBOX_SCORE_THR}] \
          [--device ${GPU_ID or CPU}]
      
    • 如果使用了 heatmap-based 模型同时设置了 --draw-heatmap ,预测的热图也会跟随关键点一同可视化出来。--det-cat-id=15 参数用来指定模型只检测 cat 类型,这是基于 COCO 数据集的数据。如果想本地保存预测结果,需要使用 --save-predictions 。视频和图片使用了同样的接口,区别在于视频推理时 ${INPUT_PATH} 既可以是本地视频文件的路径也可以是视频文件的 URL 地址。

    • python demo/topdown_demo_with_mmdet.py \
          demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \
          https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \
          configs/animal_2d_keypoint/topdown_heatmap/animalpose/td-hm_hrnet-w32_8xb64-210e_animalpose-256x256.py \
          https://download.openmmlab.com/mmpose/animal/hrnet/hrnet_w32_animalpose_256x256-1aa7f075_20210426.pth \
          --input demo/resources/<demo_dog.mp4> \
          --output-root vis_results --draw-heatmap --det-cat-id=16
      
  • 2D 脸部图片关键点识别推理

    • python demo/topdown_demo_with_mmdet.py \
          ${MMDET_CONFIG_FILE} ${MMDET_CHECKPOINT_FILE} \
          ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \
          --input ${INPUT_PATH} [--output-root ${OUTPUT_DIR}] \
          [--show] [--device ${GPU_ID or CPU}] [--save-predictions] \
          [--draw-heatmap ${DRAW_HEATMAP}] [--radius ${KPT_RADIUS}] \
          [--kpt-thr ${KPT_SCORE_THR}] [--bbox-thr ${BBOX_SCORE_THR}]
      
    • 如果使用了 heatmap-based 模型同时设置了 --draw-heatmap ,预测的热图也会跟随关键点一同可视化出来。视频和图片使用了同样的接口,区别在于视频推理时 ${INPUT_PATH} 既可以是本地视频文件的路径也可以是视频文件的 URL 地址。

    • Inferencer 提供一个更便捷的推理接口,使得用户可以绕过模型的配置文件和 checkpoint 路径直接使用 model aliases ,支持包括图片路径、视频路径、图片文件夹路径和 webcams 在内的多种输入方式,例如可以这样使用:

    • python demo/inferencer_demo.py tests/data/wflw \
          --pose2d face --vis-out-dir vis_results/wflw --radius 1
      
  • 2D 手部图片关键点识别

    • python demo/topdown_demo_with_mmdet.py \
          ${MMDET_CONFIG_FILE} ${MMDET_CHECKPOINT_FILE} \
          ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \
          --input ${INPUT_PATH} [--output-root ${OUTPUT_DIR}] \
          [--show] [--device ${GPU_ID or CPU}] [--save-predictions] \
          [--draw-heatmap ${DRAW_HEATMAP}] [--radius ${KPT_RADIUS}] \
          [--kpt-thr ${KPT_SCORE_THR}] [--bbox-thr ${BBOX_SCORE_THR}]
      
    • 如果使用了 heatmap-based 模型同时设置了 --draw-heatmap ,预测的热图也会跟随关键点一同可视化出来。如果想本地保存预测结果,需要添加 --save-predictions 。视频和图片使用了同样的接口,区别在于视频推理时 ${INPUT_PATH} 既可以是本地视频文件的路径也可以是视频文件的 URL 地址。

    • python demo/topdown_demo_with_mmdet.py \
          demo/mmdetection_cfg/cascade_rcnn_x101_64x4d_fpn_1class.py \
          https://download.openmmlab.com/mmpose/mmdet_pretrained/cascade_rcnn_x101_64x4d_fpn_20e_onehand10k-dac19597_20201030.pth \
          configs/hand_2d_keypoint/topdown_heatmap/onehand10k/td-hm_hrnetv2-w18_8xb64-210e_onehand10k-256x256.py \
          https://download.openmmlab.com/mmpose/hand/hrnetv2/hrnetv2_w18_onehand10k_256x256-30bc9c6b_20210330.pth \
          --input demo/resources/<demo_hand.mp4> \
          --output-root vis_results --show --draw-heatmap
      
    • Inferencer 提供一个更便捷的推理接口,使得用户可以绕过模型的配置文件和 checkpoint 路径直接使用 model aliases ,支持包括图片路径、视频路径、图片文件夹路径和 webcams 在内的多种输入方式,例如可以这样使用:

    • python demo/inferencer_demo.py tests/data/onehand10k \
          --pose2d hand --vis-out-dir vis_results/onehand10k \
          --bbox-thr 0.5 --kpt-thr 0.05
      
  • 2D 人体姿态 Top-Down 图片检测

    • 使用整张图片作为输入进行检测,此时输入的整张图片会被当作 bounding box 使用。

      • python demo/image_demo.py \
            ${IMG_FILE} ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \
            --out-file ${OUTPUT_FILE} \
            [--device ${GPU_ID or CPU}] \
            [--draw_heatmap]
        
    • 如果使用了 heatmap-based 模型同时设置了 --draw-heatmap ,预测的热图也会跟随关键点一同可视化出来。

    • 使用 MMDet 做人体 bounding box 检测,想要本地保存识别结果,用户需要加上 --save-predictions 。使用 MMDet 进行识别的命令如下所示:

    • python demo/topdown_demo_with_mmdet.py \
          ${MMDET_CONFIG_FILE} ${MMDET_CHECKPOINT_FILE} \
          ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \
          --input ${INPUT_PATH} \
          [--output-root ${OUTPUT_DIR}] [--save-predictions] \
          [--show] [--draw-heatmap] [--device ${GPU_ID or CPU}] \
          [--bbox-thr ${BBOX_SCORE_THR}] [--kpt-thr ${KPT_SCORE_THR}]
      
  • 2D 人体姿态 Bottom-Up 图片和视频识别检测,除了 Top-Down ,还支持 Bottom-Up 不依赖人体识别器的人体姿态预估识别,使用方式如下:

    • python demo/bottomup_demo.py \
          ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \
          --input ${INPUT_PATH} \
          [--output-root ${OUTPUT_DIR}] [--save-predictions] \
          [--show] [--device ${GPU_ID or CPU}] \
          [--kpt-thr ${KPT_SCORE_THR}]
      
  • 配置使用

    • 设置检测模型

      • 用户可以直接使用 MMDetection Model Zoo 里的识别模型,需要注意的是确保配置文件中的 DetectorNode 里的 model_config 和 model_checkpoint 需要对应起来,这样模型就会被自动下载和加载,例如:

      • # 'DetectorNode':
        # This node performs object detection from the frame image using an
        # MMDetection model.
        dict(
            type='DetectorNode',
            name='detector',
            model_config='demo/mmdetection_cfg/'
            'ssdlite_mobilenetv2-scratch_8xb24-600e_coco.py',
            model_checkpoint='https://download.openmmlab.com'
            '/mmdetection/v2.0/ssd/'
            'ssdlite_mobilenetv2_scratch_600e_coco/ssdlite_mobilenetv2_'
            'scratch_600e_coco_20210629_110627-974d9307.pth',
            input_buffer='_input_',
            output_buffer='det_result'),
        
    • 设置姿态预估模型

      • 这里我们用两个 top-down 结构的人体和动物姿态预估模型进行演示。用户可以自由使用 MMPose Model Zoo 里的模型。需要注意的是,更换模型后用户需要在对应的 pose estimate node 里添加或修改对应的 cls_names ,例如:

      • # 'TopdownPoseEstimatorNode':
        # This node performs keypoint detection from the frame image using an
        # MMPose top-down model. Detection results is needed.
        dict(
            type='TopdownPoseEstimatorNode',
            name='human pose estimator',
            model_config='configs/wholebody_2d_keypoint/'
            'topdown_heatmap/coco-wholebody/'
            'td-hm_vipnas-mbv3_dark-8xb64-210e_coco-wholebody-256x192.py',
            model_checkpoint='https://download.openmmlab.com/mmpose/'
            'top_down/vipnas/vipnas_mbv3_coco_wholebody_256x192_dark'
            '-e2158108_20211205.pth',
            labels=['person'],
            input_buffer='det_result',
            output_buffer='human_pose'),
        dict(
            type='TopdownPoseEstimatorNode',
            name='animal pose estimator',
            model_config='configs/animal_2d_keypoint/topdown_heatmap/'
            'animalpose/td-hm_hrnet-w32_8xb64-210e_animalpose-256x256.py',
            model_checkpoint='https://download.openmmlab.com/mmpose/animal/'
            'hrnet/hrnet_w32_animalpose_256x256-1aa7f075_20210426.pth',
            labels=['cat', 'dog', 'horse', 'sheep', 'cow'],
            input_buffer='human_pose',
            output_buffer='animal_pose'),
        
  • 测试摄像头和显示器连接,使用如下命令就能完成检测:

    • python demo/webcam_api_demo.py --config demo/webcam_cfg/test_camera.py
      
  • 本机没有摄像头怎么办

    • 用户可以在自己手机安装上一些 app 就能替代摄像头,例如 Camo 和 DroidCam 。
      ‘configs/animal_2d_keypoint/topdown_heatmap/’
      ‘animalpose/td-hm_hrnet-w32_8xb64-210e_animalpose-256x256.py’,
      model_checkpoint=‘https://download.openmmlab.com/mmpose/animal/’
      ‘hrnet/hrnet_w32_animalpose_256x256-1aa7f075_20210426.pth’,
      labels=[‘cat’, ‘dog’, ‘horse’, ‘sheep’, ‘cow’],
      input_buffer=‘human_pose’,
      output_buffer=‘animal_pose’),
      
      
  • 测试摄像头和显示器连接,使用如下命令就能完成检测:

    • python demo/webcam_api_demo.py --config demo/webcam_cfg/test_camera.py
      
  • 本机没有摄像头怎么办

    • 用户可以在自己手机安装上一些 app 就能替代摄像头,例如 Camo 和 DroidCam 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/620510.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

告别加班!9款Figma汉化插件助你高效工作,提升生产力!

Figma是一款极受设计师欢迎的设计工具&#xff0c;而Figma中文版即时设计则是在Figma基础上改进而来&#xff0c;有着众多的Figma汉化插件&#xff0c;可以加速设计工作&#xff0c;让每位设计师完成更好的创作。 打开即时设计官网首页&#xff0c;点击【设计社区】-【插件广场…

虚函数表详解及其应用场景

目录 概述1. 虚函数表概述2. 虚函数表的实现原理2.1. 虚函数的声明和定义2.2. 虚函数表的创建和初始化2.3. 虚函数调用的过程 3. 虚函数表的应用场景3.1. 多态性3.2. 基类指针和引用的使用3.3. 动态绑定3.4. 接口定义 结论 概述 在面向对象编程中&#xff0c;虚函数表&#xf…

java-JDBC

java-JDBC 1. JDBC概念 JDBC 就是使用Java语言操作关系型数据库的一套API 全称&#xff1a;( Java DataBase Connectivity ) Java 数据库连接 sun公司就指定了一套标准接口&#xff08;JDBC&#xff09;&#xff0c;JDBC中定义了所有操作关系型数据库的规则。 我们需要使用接口…

人群聚集监测预警算法 python

人群聚集监测预警系统采用pythonopencv网络模型AI视频智能分析技术&#xff0c;人群聚集监测预警算法对人员聚集情况进行实时监测&#xff0c;当人群聚集过于密集时&#xff0c;系统将自动发出警报。OpenCV基于C实现&#xff0c;同时提供python, Ruby, Matlab等语言的接口。Ope…

R语言 tidyverse系列学习笔记(系列1)

tidyverse 译 “洁净的宇宙” > “极乐净土” 以 iris 鸢尾花数据集为例 ** 查看数据集** ** 查看维度dimention** dim(iris)iris 数据集有150个对象&#xff08;observation&#xff09;&#xff0c;5列 ( Sepal.Length , Sepal.Width , Petal.Length , Petal.Width , S…

阿里服务器配置服务器自启动

一开始 是在 /etc/rc.local 文件中添加的如下脚本 bash /mnt/cangjie-server/action.sh start bash /usr/local/nginx/sbin/nginx pm2 start npm--name"cangjieWeb"run start 启动服务器&#xff0c;服务并没有执行。 后面把执行脚本的 bash 指令去掉 如下&#xf…

Linux内核中断和Linux内核定时器

目录 Linux内核中断 Linux内核定时器 Linux内核中断 int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev) 功能&#xff1a;注册中断 参数&#xff1a; irq : 软中断号 gpio的软中断号 软中断号 gpio_to_i…

期末复习样卷

期末复习样卷 目录 期末复习样卷选择题简答题1. 画E-R图并将其转换为适当的关系模型2. 规范化模式分解——教学关系&#xff08;学号&#xff0c;姓名&#xff0c;年龄&#xff0c;性别&#xff0c;系别&#xff0c;系主任&#xff0c;课程名&#xff0c;成绩&#xff09;3.关系…

重装Windows系统

1.前言 有的时候&#xff0c;面对杂乱的文件系统&#xff0c;整理是十分困难的…… 有的时候&#xff0c;下载软件的时候会附带上某一些病毒、木马…… 有的时候&#xff0c;不满于更新后的系统…… 这些种种都可以使用重装系统解决&#xff0c;接下来我来带您学习重装windows…

煤炭价格学习

大佬发表时间在2022.11.17 神华月线&#xff0c;因为没有送配股&#xff0c;所以肯定是除权看的&#xff08;前复权看的不要跟我谈技术&#xff0c;因为你不配&#xff09; 除权&#xff0c;前复权&#xff0c;后复权 理解这三者区别之前&#xff0c;首先我们要简单了解 除权和…

【String字符串之后续】

我们继续上一篇文章为大家讲解&#xff0c;String字符串的相关知识&#xff0c;希望大家有所收获&#x1f49e;&#x1f49e;&#x1f49e; 字符串前篇的链接: link 目录 1.字符串的替换2.字符串的拆分3.字符串截取4.去掉空格5.String的不可变性6. 字符串的修改7.StringBuilde…

STL:string类使用

编码&#xff1a; ASCII unicode–utf-8 utf-16----一个字符2个字符 utf-32----一个字符4个字节 gbk–中文编码表 string&#xff1a; 是一个特殊的容器&#xff0c;对数据&#xff08;字符数组&#xff09;和库函数&#xff08;strlen等&#xff09;进行封装 STL提供的内容…

OpenStack部署(三)

OpenStack部署 6. Neutron6.1 创建Neutron数据库并授权6.2 获得admin凭证6.3 创建 neutron 用户并设置密码6.4 添加admin角色到neutron 用户6.5 创建neutron服务实体6.6 创建网络服务API端点6.7 安装并配置neutron服务6.8 链接plugin.ini文件6.9 初始化neutron数据库6.10 重启计…

连续两年!PingCAP 入选 Gartner 云数据库“客户之声”,获评“卓越表现者”最高分

近日&#xff0c;全球权威信息技术研究与咨询机构 Gartner 发布了云数据库市场领域 2023 Gartner Peer Insights™“Voice of the Customer” 报告&#xff0c;PingCAP 在报告中获得的客户总体评分达到 4.9 分&#xff08;满分 5 分&#xff09;&#xff0c;在所有入选企业中位…

CBCGPCaptionBar 使用实例说明

CBCGPCaptionBar的位置如下&#xff1a; 如图区域就是 MainFrame.h中声明&#xff1a; CBCGPCaptionBar m_wndCaptionBar; MainFrame.cpp中创建显示控件&#xff1a; BOOL CMainFrame::CreateCaptionBar () { if (!m_wndCaptionBar.Create (WS_CHILD | WS_V…

力扣第三天 242.有效字母异位词 349 两个数组的交集

目录 1.242. 有效的字母异位词 2.349. 两个数组的交集 - 力扣&#xff08;LeetCode&#xff09;​​​​​​ 使用算法笔记&#xff1a; 总结&#xff1a; 1.242. 有效的字母异位词 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 注意…

15. 算法之排序算法

前言 排序是在软件开发中经常遇到的需求。比如基于订单的创建时间倒排&#xff0c;基于金额大小排序等等&#xff0c;那么这些排序底层是怎么写的呢&#xff0c;本节&#xff0c;我们就常用排序算法展开介绍。 1. 冒泡排序 1.1 算法思想 冒泡排序是最基础的排序算法。冒泡排…

HashMap 的底层原理和源码分析

tip&#xff1a;作为程序员一定学习编程之道&#xff0c;一定要对代码的编写有追求&#xff0c;不能实现就完事了。我们应该让自己写的代码更加优雅&#xff0c;即使这会费时费力。 推荐&#xff1a;体系化学习Java&#xff08;Java面试专题&#xff09; 文章目录 一、HashMap…

【迷宫】地下迷宫游戏-微信小程序开发流程详解

可曾记得&#xff0c;小时候上学路边买的透明铅笔盒&#xff0c;里面内嵌了一个小球&#xff0c;它用重力可从起点滚动到终点&#xff0c;对小朋友来说是感觉有趣的&#xff0c;在这个游戏的基础上&#xff0c;弄一款微信小程序的迷宫探索游戏试试&#xff0c;在不同关卡的迷宫…

14 【Vuex】

1.理解 Vuex 1.1 Vuex 是什么 概念&#xff1a;专门在Vue中实现集中式状态&#xff08;数据&#xff09;管理的一个Vue插件&#xff0c;对Vue应用中多个组件的共享状态进行集中式的管理&#xff08;读/写&#xff09;&#xff0c;也是一种组件间通信的方式&#xff0c;且适用…