以下連結是個人關于PVNet(6D姿态估計) 所有見解,如有錯誤歡迎大家指出,我會第一時間糾正。有興趣的朋友可以加微信:a944284742互相讨論技術。若是幫助到了你什麼,一定要記得點贊!因為這是對我最大的鼓勵。 文 末 附 帶 \color{blue}{文末附帶} 文末附帶 公 衆 号 − \color{blue}{公衆号 -} 公衆号− 海 量 資 源 。 \color{blue}{ 海量資源}。 海量資源。
姿态估計2-00:PVNet(6D姿态估計)-目錄-史上最新無死角講解
代碼注釋
根據上篇部落格的介紹,我們可以看到 train_net.py 中的如下代碼:
# 建立訓練以及評估資料集疊代器
train_loader = make_data_loader(cfg, is_train=True, max_iter=cfg.ep_iter)
val_loader = make_data_loader(cfg, is_train=False)
本人的講解都是基于 linemod 資料集,是以上述疊代器的建立是在data/lib/datasets/linemod/pvnet.py中實作,該代碼的注釋如下:
import torch.utils.data as data
from pycocotools.coco import COCO
import numpy as np
import os
from PIL import Image
from lib.utils.pvnet import pvnet_data_utils, pvnet_linemod_utils, visualize_utils
from lib.utils.linemod import linemod_config
from lib.datasets.augmentation import crop_or_padding_to_fixed_size, rotate_instance, crop_resize_instance_v1
import random
import torch
from lib.config import cfg
class Dataset(data.Dataset):
def __init__(self, ann_file, data_root, split, transforms=None):
super(Dataset, self).__init__()
# data_root = data/linemod/cat/JPEGImages, 訓練或者測試圖檔路徑
self.data_root = data_root
# 表示該資料集是分割出來的訓練集還是測試集
self.split = split
# 加載COCO注釋檔案ann_file = data/linemod/cat/train.json
self.coco = COCO(ann_file)
# 獲得圖檔的所有ids
self.img_ids = np.array(sorted(self.coco.getImgIds()))
# 用于資料預處理,
self._transforms = transforms
# 指派配置資訊
self.cfg = cfg
def read_data(self, img_id):
# 根據圖檔的id,獲得對應圖像注釋的ids
ann_ids = self.coco.getAnnIds(imgIds=img_id)
# 因為對于每張圖檔,隻有一個ann_ids,是以後面加了[0]
anno = self.coco.loadAnns(ann_ids)[0]
# 獲得圖像的路徑
path = self.coco.loadImgs(int(img_id))[0]['file_name']
inp = Image.open(path)
# 獲去圖檔标出的2d關鍵點以及3d關鍵點坐标
kpt_2d = np.concatenate([anno['fps_2d'], [anno['center_2d']]], axis=0)
# 根據注釋的cls,獲得類别的idx标簽
cls_idx = linemod_config.linemod_cls_names.index(anno['cls']) + 1
# 資料中存在三種type[real, fuse, render]
mask = pvnet_data_utils.read_linemod_mask(anno['mask_path'], anno['type'], cls_idx)
return inp, kpt_2d, mask
def __getitem__(self, index_tuple):
# 獲得圖檔索引,以及高寬(随機獲得,用于資料增強),
index, height, width = index_tuple
# 獲得圖檔id
img_id = self.img_ids[index]
# 獲得圖檔像素,2d關鍵點以及 mask
img, kpt_2d, mask = self.read_data(img_id)
# 如果為訓練則進行資料增強
if self.split == 'train':
inp, kpt_2d, mask = self.augment(img, mask, kpt_2d, height, width)
else:
inp = img
# 如果設定了transforms則執行
if self._transforms is not None:
inp, kpt_2d, mask = self._transforms(inp, kpt_2d, mask)
# 根據mask計算出屬于mask中每個像素到對應關鍵點的vector, 即論文中的Vk(p)
vertex = pvnet_data_utils.compute_vertex(mask, kpt_2d).transpose(2, 0, 1)
ret = {'inp': inp, 'mask': mask.astype(np.uint8), 'vertex': vertex, 'img_id': img_id, 'meta': {}}
# visualize_utils.visualize_linemod_ann(torch.tensor(inp), kpt_2d, mask, True)
return ret
def __len__(self):
return len(self.img_ids)
def augment(self, img, mask, kpt_2d, height, width):
"""
資料增強
:param img: 像素
:param mask: 圖像掩碼
:param kpt_2d: 二維關鍵點坐标,最後一個為中心坐标
:return:
"""
# add one column to kpt_2d for convenience to calculate
# kpt_2d[9,2]-->hcoords[9,3],增加一列,并且該列全部為1
hcoords = np.concatenate((kpt_2d, np.ones((9, 1))), axis=-1)
# 對像素的格式進行轉換
img = np.asarray(img).astype(np.uint8)
# 計算是否存屬于前景物體,即foregroun>0
foreground = np.sum(mask)
# randomly mask out to add occlusion
# foreground>0,表示存在前景物體
if foreground > 0:
# 進行随機[self.cfg.train.rotate_min, self.cfg.train.rotate_max]之間的角度旋轉,
# img, mask, mask 都會進行旋轉
img, mask, hcoords = rotate_instance(img, mask, hcoords, self.cfg.train.rotate_min, self.cfg.train.rotate_max)
# 随機進行crop, resize操作
img, mask, hcoords = crop_resize_instance_v1(img, mask, hcoords, height, width,
self.cfg.train.overlap_ratio,
self.cfg.train.resize_ratio_min,
self.cfg.train.resize_ratio_max)
# 如果隻有背景,沒有前景。則進行crop,padding操作,把圖檔變換到固定大小
else:
img, mask = crop_or_padding_to_fixed_size(img, mask, height, width)
kpt_2d = hcoords[:, :2]
return img, kpt_2d, mask
代碼講解
總的說,就是獲得訓練圖像的像素,以及對應的标簽,其中标簽包含了兩個部分,分别為vertex(向量域),以及語義分割得到的mask掩碼。vertex與mask的 W , H W,H W,H 是相等的。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2YfNWawNyZwpmL5kDN1ADMyMTMzIjMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)