Team Ai
Apppublic

MLVLab/Human_Object_Interaction

sourceHugging Faceapache-2.0updated 3y agoView on Hugging Face
1likes
vcoco.py468 linesDownload Raw Back to datasets
1# Copyright (c) Kakaobrain, Inc. and its affiliates. All Rights Reserved2"""3V-COCO dataset which returns image_id for evaluation.4"""5from pathlib import Path6 7from PIL import Image8import os9import numpy as np10import json11import torch12import torch.utils.data13import torchvision14 15from torch.utils.data import Dataset16from pycocotools.coco import COCO17from pycocotools import mask as coco_mask18 19from hotr.data.datasets import builtin_meta20import hotr.data.transforms.transforms as T21 22class VCocoDetection(Dataset):23    def __init__(self,24                 img_folder,25                 ann_file,26                 all_file,27                 filter_empty_gt=True,28                 transforms=None):29        self.img_folder = img_folder30        self.file_meta = dict()31        self._transforms = transforms32 33        self.ann_file = ann_file34        self.all_file = all_file35        self.filter_empty_gt = filter_empty_gt36 37        # COCO initialize38        self.coco = COCO(self.all_file)39        self.COCO_CLASSES = builtin_meta._get_coco_instances_meta()['coco_classes']40        self.file_meta['coco_classes'] = self.COCO_CLASSES41 42        # Load V-COCO Dataset43        self.vcoco_all = self.load_vcoco(self.ann_file)44 45        # Save COCO annotation data46        self.image_ids = sorted(list(set(self.vcoco_all[0]['image_id'].reshape(-1))))47 48        # Filter Data49        if filter_empty_gt:50            self.filter_image_id()51        self.img_infos = self.load_annotations()52 53        # Refine Data54        self.save_action_name()55        self.mapping_inst_action_to_action()56        self.load_subobj_classes()57        self.CLASSES = self.act_list58 59    ############################################################################60    # Load V-COCO Dataset61    ############################################################################62    def load_vcoco(self, dir_name=None):63        with open(dir_name, 'rt') as f:64            vsrl_data = json.load(f)65 66        for i in range(len(vsrl_data)):67            vsrl_data[i]['role_object_id'] = np.array(vsrl_data[i]['role_object_id']).reshape((len(vsrl_data[i]['role_name']),-1)).T68            for j in ['ann_id', 'label', 'image_id']:69                vsrl_data[i][j] = np.array(vsrl_data[i][j]).reshape((-1,1))70 71        return vsrl_data72 73    ############################################################################74    # Refine Data75    ############################################################################76    def save_action_name(self):77        self.inst_act_list = list()78        self.act_list = list()79 80        # add instance action human classes81        self.num_subject_act = 082        for vcoco in self.vcoco_all:83            self.inst_act_list.append('human_' + vcoco['action_name'])84            self.num_subject_act += 185 86        # add instance action object classes87        for vcoco in self.vcoco_all:88            if len(vcoco['role_name']) == 3:89                self.inst_act_list.append('object_' + vcoco['action_name']+'_'+vcoco['role_name'][1])90                self.inst_act_list.append('object_' + vcoco['action_name']+'_'+vcoco['role_name'][2])91            elif len(vcoco['role_name']) < 2:92                continue93            else:94                self.inst_act_list.append('object_' + vcoco['action_name']+'_'+vcoco['role_name'][-1]) # when only two roles95 96        # add action classes97        for vcoco in self.vcoco_all:98            if len(vcoco['role_name']) == 3:99                self.act_list.append(vcoco['action_name']+'_'+vcoco['role_name'][1])100                self.act_list.append(vcoco['action_name']+'_'+vcoco['role_name'][2])101            else:102                self.act_list.append(vcoco['action_name']+'_'+vcoco['role_name'][-1])103 104        # add to meta105        self.file_meta['action_classes'] = self.act_list106 107    def mapping_inst_action_to_action(self):108        sub_idx = 0109        obj_idx = self.num_subject_act110 111        self.sub_label_to_action = list()112        self.obj_label_to_action = list()113 114        for vcoco in self.vcoco_all:115            role_name = vcoco['role_name']116 117            self.sub_label_to_action.append(sub_idx)118            if len(role_name) == 3 :119                self.sub_label_to_action.append(sub_idx)120                self.obj_label_to_action.append(obj_idx)121                self.obj_label_to_action.append(obj_idx+1)122                obj_idx += 2123            elif len(role_name) == 2:124                self.obj_label_to_action.append(obj_idx)125                obj_idx += 1126            else:127                self.obj_label_to_action.append(0)128 129            sub_idx += 1130 131    def load_subobj_classes(self):132        self.vcoco_labels = dict()133        for img in self.image_ids:134            self.vcoco_labels[img] = dict()135            self.vcoco_labels[img]['boxes'] = np.empty((0, 4), dtype=np.float32)136            self.vcoco_labels[img]['categories'] = np.empty((0), dtype=np.int32)137 138            ann_ids = self.coco.getAnnIds(imgIds=img, iscrowd=None)139            objs = self.coco.loadAnns(ann_ids)140 141            valid_ann_ids = []142 143            for i, obj in enumerate(objs):144                if 'ignore' in obj and obj['ignore'] == 1: continue145 146                x1 = obj['bbox'][0]147                y1 = obj['bbox'][1]148                x2 = x1 + np.maximum(0., obj['bbox'][2] - 1.)149                y2 = y1 + np.maximum(0., obj['bbox'][3] - 1.)150 151                if obj['area'] > 0 and x2 > x1 and y2 > y1:152                    bbox = np.array([x1, y1, x2, y2]).reshape(1, -1)153                    cls = obj['category_id']154                    self.vcoco_labels[img]['boxes'] = np.concatenate([self.vcoco_labels[img]['boxes'], bbox], axis=0)155                    self.vcoco_labels[img]['categories'] = np.concatenate([self.vcoco_labels[img]['categories'], [cls]], axis=0)156 157                    valid_ann_ids.append(ann_ids[i])158 159            num_valid_objs = len(valid_ann_ids)160 161            self.vcoco_labels[img]['agent_actions'] = -np.ones((num_valid_objs, self.num_action()), dtype=np.int32)162            self.vcoco_labels[img]['obj_actions'] = np.zeros((num_valid_objs, self.num_action()), dtype=np.int32)163            self.vcoco_labels[img]['role_id'] = -np.ones((num_valid_objs, self.num_action()), dtype=np.int32)164 165            for ix, ann_id in enumerate(valid_ann_ids):166                in_vcoco = np.where(self.vcoco_all[0]['ann_id'] == ann_id)[0]167                if in_vcoco.size > 0:168                    self.vcoco_labels[img]['agent_actions'][ix, :] = 0169 170                    agent_act_id = 0171                    obj_act_id = -1172                    for i, x in enumerate(self.vcoco_all):173                        has_label = np.where(np.logical_and(x['ann_id'] == ann_id, x['label'] == 1))[0]174                        if has_label.size > 0:175                            assert has_label.size == 1176                            rids = x['role_object_id'][has_label]177 178                            if rids.shape[1] == 3:179                                self.vcoco_labels[img]['agent_actions'][ix, agent_act_id] = 1180                                self.vcoco_labels[img]['agent_actions'][ix, agent_act_id+1] = 1181                                agent_act_id += 2182                            else:183                                self.vcoco_labels[img]['agent_actions'][ix, agent_act_id] = 1184                                agent_act_id += 1185                                if rids.shape[1] == 1 : obj_act_id += 1186 187                            for j in range(1, rids.shape[1]):188                                obj_act_id += 1189                                if rids[0, j] == 0: continue # no role190                                aid = np.where(valid_ann_ids == rids[0, j])[0]191 192                                self.vcoco_labels[img]['role_id'][ix, obj_act_id] = aid193                                self.vcoco_labels[img]['obj_actions'][aid, obj_act_id] = 1194 195                        else:196                            rids = x['role_object_id'][0]197                            if rids.shape[0] == 3:198                                agent_act_id += 2199                                obj_act_id += 2200                            else:201                                agent_act_id += 1202                                obj_act_id += 1203 204    ############################################################################205    # Annotation Loader206    ############################################################################207    # >>> 1. instance208    def load_instance_annotations(self, image_index):209        num_ann = self.vcoco_labels[image_index]['boxes'].shape[0]210        inst_action = np.zeros((num_ann, self.num_inst_action()), np.int)211        inst_bbox = np.zeros((num_ann, 4), dtype=np.float32)212        inst_category = np.zeros((num_ann, ), dtype=np.int)213 214        for idx in range(num_ann):215            inst_bbox[idx] = self.vcoco_labels[image_index]['boxes'][idx]216            inst_category[idx]= self.vcoco_labels[image_index]['categories'][idx] #+ 1 # category 1 ~ 81217 218            if inst_category[idx] == 1:219                act = self.vcoco_labels[image_index]['agent_actions'][idx]220                inst_action[idx, :self.num_subject_act] = act[np.unique(self.sub_label_to_action, return_index=True)[1]]221 222                # when person is the obj223                act = self.vcoco_labels[image_index]['obj_actions'][idx] # when person is the obj224                if act.any():225                    inst_action[idx, self.num_subject_act:] = act[np.nonzero(self.obj_label_to_action)[0]]226                    if inst_action[idx, :self.num_subject_act].sum(axis=-1) < 0:227                        inst_action[idx, :self.num_subject_act] = 0228            else:229                act = self.vcoco_labels[image_index]['obj_actions'][idx]230                inst_action[idx, self.num_subject_act:] = act[np.nonzero(self.obj_label_to_action)[0]]231 232        # >>> For Objects that are in COCO but not in V-COCO,233        # >>> Human -> [-1 * 26, 0 * 25]234        # >>> Object -> [0 * 51]235        # >>> Don't return anything for actions with max 0 or max -1236        max_val = inst_action.max(axis=1)237        if (max_val > 0).sum() == 0:238            print(f"No Annotations for {image_index}")239            print(inst_action)240            print(self.vcoco_labels[image_index]['agent_actions'][idx])241            print(self.vcoco_labels[image_index]['obj_actions'][idx])242 243        return inst_bbox[max_val > 0], inst_category[max_val > 0], inst_action[max_val > 0]244 245    # >>> 2. pair246    def load_pair_annotations(self, image_index):247        num_ann = self.vcoco_labels[image_index]['boxes'].shape[0]248        pair_action = np.zeros((0, self.num_action()), np.int)249        pair_bbox = np.zeros((0, 8), dtype=np.float32)250        pair_target = np.zeros((0, ), dtype=np.int)251 252        for idx in range(num_ann):253            h_box = self.vcoco_labels[image_index]['boxes'][idx]254            h_cat = self.vcoco_labels[image_index]['categories'][idx]255            if h_cat != 1 : continue # human_id = 1256 257            h_act = self.vcoco_labels[image_index]['agent_actions'][idx]258            if np.any((h_act==-1)) : continue259 260            o_act = dict()261            for aid in range(self.num_action()):262                if h_act[aid] == 0 : continue263                o_id = self.vcoco_labels[image_index]['role_id'][idx, aid]264                if o_id not in o_act : o_act[o_id] = list()265                o_act[o_id].append(aid)266 267            for o_id in o_act.keys():268                if o_id == -1:269                    o_box = -np.ones((4, ))270                    o_cat = -1 # target is background271                else:272                    o_box = self.vcoco_labels[image_index]['boxes'][o_id]273                    o_cat = self.vcoco_labels[image_index]['categories'][o_id] # category 0 ~ 80274 275                box = np.concatenate([h_box, o_box]).astype(np.float32)276                act = np.zeros((1, self.num_action()), np.int)277                tar = np.zeros((1, ), np.int)278                tar[0] = o_cat #+ 1 # category 1 ~ 81279                for o_aid in o_act[o_id] : act[0, o_aid] = 1280 281                pair_action = np.concatenate([pair_action, act], axis=0)282                pair_bbox = np.concatenate([pair_bbox, np.expand_dims(box, axis=0)], axis=0)283                pair_target = np.concatenate([pair_target, tar], axis=0)284 285        return pair_bbox, pair_action, pair_target286 287    # >>> 3. image infos288    def load_annotations(self):289        img_infos = []290        for i in self.image_ids:291            info = self.coco.loadImgs([i])[0]292            img_infos.append(info)293        return img_infos294 295    ############################################################################296    # Check Method297    ############################################################################298    def sum_action_ann_for_id(self, find_idx):299        sum = 0300        for action_ann in self.vcoco_all:301            img_ids = action_ann['image_id']302            img_labels = action_ann['label']303 304            final_inds = img_ids[img_labels == 1]305 306            if (find_idx in final_inds):307                sum += 1308        # sum of class-wise existence309        return (sum > 0)310 311    def filter_image_id(self):312        empty_gt_list = []313        for img_id in self.image_ids:314            if not self.sum_action_ann_for_id(img_id):315                empty_gt_list.append(img_id)316 317        for remove_id in empty_gt_list:318            rm_idx = self.image_ids.index(remove_id)319            self.image_ids.remove(remove_id)320 321    ############################################################################322    # Preprocessing323    ############################################################################324    def prepare_img(self, idx):325        img_info = self.img_infos[idx]326        image = Image.open(os.path.join(self.img_folder, img_info['file_name'])).convert('RGB')327        target = self.get_ann_info(idx)328 329        w, h = image.size330        target["orig_size"] = torch.as_tensor([int(h), int(w)])331        target["size"] = torch.as_tensor([int(h), int(w)])332 333        if self._transforms is not None:334            img, target = self._transforms(image, target) # "size" gets converted here335 336        return img, target337 338    ############################################################################339    # Get Method340    ############################################################################341    def __getitem__(self, idx):342        img, target = self.prepare_img(idx)343        return img, target344 345    def __len__(self):346        return len(self.image_ids)347 348    def get_human_label_idx(self):349        return self.sub_label_to_action350 351    def get_object_label_idx(self):352        return self.obj_label_to_action353 354    def get_image_ids(self):355        return self.image_ids356 357    def get_categories(self):358        return self.COCO_CLASSES359 360    def get_inst_action(self):361        return self.inst_act_list362 363    def get_actions(self):364        return self.act_list365 366    def get_human_action(self):367        return self.inst_act_list[:self.num_subject_act]368 369    def get_object_action(self):370        return self.inst_act_list[self.num_subject_act:]371 372    def get_ann_info(self, idx):373        img_idx = int(self.image_ids[idx])374 375        # load each annotation376        inst_bbox, inst_label, inst_actions = self.load_instance_annotations(img_idx)377        pair_bbox, pair_actions, pair_targets = self.load_pair_annotations(img_idx)378 379        sample = {380            'image_id' : torch.tensor([img_idx]),381            'boxes': torch.as_tensor(inst_bbox, dtype=torch.float32),382            'labels': torch.tensor(inst_label, dtype=torch.int64),383            'inst_actions': torch.tensor(inst_actions, dtype=torch.int64),384            'pair_boxes': torch.as_tensor(pair_bbox, dtype=torch.float32),385            'pair_actions': torch.tensor(pair_actions, dtype=torch.int64),386            'pair_targets': torch.tensor(pair_targets, dtype=torch.int64),387        }388 389        return sample390 391    ############################################################################392    # Number Method393    ############################################################################394    def num_category(self):395        return len(self.COCO_CLASSES)396 397    def num_action(self):398        return len(self.act_list)399 400    def num_inst_action(self):401        return len(self.inst_act_list)402 403    def num_human_act(self):404        return len(self.inst_act_list[:self.num_subject_act])405 406    def num_object_act(self):407        return len(self.inst_act_list[self.num_subject_act:])408 409def make_hoi_transforms(image_set):410    normalize = T.Compose([411        T.ToTensor(),412        T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])413    ])414 415    scales = [480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800]416 417    if image_set == 'train':418        return T.Compose([419            T.RandomHorizontalFlip(),420            T.ColorJitter(.4, .4, .4),421            T.RandomSelect(422                T.RandomResize(scales, max_size=1333),423                T.Compose([424                    T.RandomResize([400, 500, 600]),425                    T.RandomSizeCrop(384, 600),426                    T.RandomResize(scales, max_size=1333),427                ])428            ),429            normalize,430        ])431 432    if image_set == 'val':433        return T.Compose([434            T.RandomResize([800], max_size=1333),435            normalize,436        ])437 438    if image_set == 'test':439        return T.Compose([440            T.RandomResize([800], max_size=1333),441            normalize,442        ])443 444    raise ValueError(f'unknown {image_set}')445 446def build(image_set, args):447    root = Path(args.data_path)448    assert root.exists(), f'provided V-COCO path {root} does not exist'449    PATHS = {450        "train": (root / "coco/images/train2014/", root / "data/vcoco" / 'vcoco_trainval.json'),451        "val": (root / "coco/images/val2014", root / "data/vcoco" / 'vcoco_test.json'),452        "test": (root / "coco/images/val2014", root / "data/vcoco" / 'vcoco_test.json'),453    }454 455    img_folder, ann_file = PATHS[image_set]456    all_file = root / "data/instances_vcoco_all_2014.json"457    dataset = VCocoDetection(458        img_folder = img_folder,459        ann_file = ann_file,460        all_file = all_file,461        filter_empty_gt=True,462        transforms = make_hoi_transforms(image_set)463    )464    dataset.file_meta['dataset_file'] = args.dataset_file465    dataset.file_meta['image_set'] = image_set466 467    return dataset468