Download model/dataset.py from stumpferWinkel/grasp: direct link, hf CLI and curl.
- Browser
- Download file 54.1 kB
-
https://huggingface.co/stumpferWinkel/grasp/resolve/main/model/dataset.py
- Command line
-
hf download hf://stumpferWinkel/grasp/model/dataset.py
-
curl -L -o dataset.py https://huggingface.co/stumpferWinkel/grasp/resolve/main/model/dataset.py
54.1 kB
| import os | |
| from typing import List, Union | |
| import json | |
| import cv2 | |
| import lmdb | |
| import numpy as np | |
| import pyarrow as pa | |
| import torch | |
| from torch.utils.data import Dataset | |
| from copy import deepcopy | |
| import functools | |
| from skimage.measure import regionprops | |
| from shapely.geometry import Polygon | |
| from skimage.draw import polygon | |
| from skimage.filters import gaussian | |
| import matplotlib.pyplot as plt | |
| from .simple_tokenizer import SimpleTokenizer as _Tokenizer | |
| from .OCID_sub_class_dict import cnames, colors, subnames, sub_to_class | |
| from .augmentation import DataAugmentor | |
| info = { | |
| 'refcoco': { | |
| 'train': 42404, | |
| 'val': 3811, | |
| 'val-test': 3811, | |
| 'testA': 1975, | |
| 'testB': 1810 | |
| }, | |
| 'refcoco+': { | |
| 'train': 42278, | |
| 'val': 3805, | |
| 'val-test': 3805, | |
| 'testA': 1975, | |
| 'testB': 1798 | |
| }, | |
| 'refcocog_u': { | |
| 'train': 42226, | |
| 'val': 2573, | |
| 'val-test': 2573, | |
| 'test': 5023 | |
| }, | |
| 'refcocog_g': { | |
| 'train': 44822, | |
| 'val': 5000, | |
| 'val-test': 5000 | |
| }, | |
| 'cocostuff': { | |
| "train": 965042, | |
| 'val': 42095, | |
| 'val-test': 42095 | |
| } | |
| } | |
| _tokenizer = _Tokenizer() | |
| def tokenize(texts: Union[str, List[str]], | |
| context_length: int = 77, | |
| truncate: bool = False) -> torch.LongTensor: | |
| """ | |
| Returns the tokenized representation of given input string(s) | |
| Parameters | |
| ---------- | |
| texts : Union[str, List[str]] | |
| An input string or a list of input strings to tokenize | |
| context_length : int | |
| The context length to use; all CLIP models use 77 as the context length | |
| truncate: bool | |
| Whether to truncate the text in case its encoding is longer than the context length | |
| Returns | |
| ------- | |
| A two-dimensional tensor containing the resulting tokens, shape = [number of input strings, context_length] | |
| """ | |
| if isinstance(texts, str): | |
| texts = [texts] | |
| sot_token = _tokenizer.encoder["<|startoftext|>"] | |
| eot_token = _tokenizer.encoder["<|endoftext|>"] | |
| all_tokens = [[sot_token] + _tokenizer.encode(text) + [eot_token] | |
| for text in texts] | |
| result = torch.zeros(len(all_tokens), context_length, dtype=torch.long) | |
| for i, tokens in enumerate(all_tokens): | |
| if len(tokens) > context_length: | |
| if truncate: | |
| tokens = tokens[:context_length] | |
| tokens[-1] = eot_token | |
| else: | |
| raise RuntimeError( | |
| f"Input {texts[i]} is too long for context length {context_length}" | |
| ) | |
| result[i, :len(tokens)] = torch.tensor(tokens) | |
| return result | |
| def loads_pyarrow(buf): | |
| """ | |
| Args: | |
| buf: the output of `dumps`. | |
| """ | |
| return pa.deserialize(buf) | |
| class RefOCIDGraspDataset(Dataset): | |
| def __init__(self, root_path, input_size, word_length, mode="train"): | |
| super().__init__() | |
| json_path = os.path.join(root_path, f"{mode}_expressions.json") | |
| with open(json_path, "r") as f: | |
| self.meta_data = json.load(f) | |
| self.root_path = root_path | |
| self.keys = list(self.meta_data.keys()) | |
| self.input_size = (input_size, input_size) | |
| self.word_length = word_length | |
| self.mode = mode | |
| self.cls_names = cls_names | |
| self.colors = colors | |
| self.mean = torch.tensor([0.48145466, 0.4578275, | |
| 0.40821073]).reshape(3, 1, 1) | |
| self.std = torch.tensor([0.26862954, 0.26130258, | |
| 0.27577711]).reshape(3, 1, 1) | |
| self.target_save_dir = os.path.join("./", mode) | |
| os.makedirs(self.target_save_dir, exist_ok=True) | |
| def __len__(self): | |
| return len(self.keys) | |
| def visualization(self, rgb, depth, masks, rects, grasp_masks, bbox, obj_cls, sentence): | |
| cls_list = list(self.cls_names.keys()) | |
| print(rgb.shape, depth.shape, len(rects), masks.shape) | |
| mask_color = self.colors[str(obj_cls)] | |
| rgb_with_grasp = deepcopy(rgb) | |
| color_masks = np.repeat(masks[:, :, np.newaxis], 3, axis=-1) * mask_color | |
| rgb = (rgb * 255).astype(np.uint8) | |
| img_fuse = (rgb * 0.3 + color_masks * 0.7).astype(np.uint8) | |
| x1, y1, x2, y2 = bbox | |
| cv2.rectangle(img_fuse, (x1, y1), (x2, y2), (255, 0, 0), 2) | |
| print(f'\nimg shape: {rgb.shape}') | |
| print('----------------boxes----------------') | |
| for rect in rects: | |
| print(rect) | |
| print('----------------labels---------------') | |
| print([cls_list[int(i)] for i in [obj_cls]], '\n') | |
| for rect in rects: | |
| name = cls_list[int(obj_cls)] | |
| color = self.colors[str(obj_cls)] | |
| center_x, center_y, width, height, theta, cls_id = rect | |
| box = ((center_x, center_y), (width, height), -(theta+180)) | |
| box = cv2.boxPoints(box) | |
| box = np.int0(box) | |
| cv2.drawContours(rgb_with_grasp, [box], 0, color.tolist(), 2) | |
| fig = plt.figure(figsize=(25, 10)) | |
| ax = fig.add_subplot(2, 4, 1) | |
| ax.imshow(rgb) | |
| ax.set_title('RGB') | |
| ax.axis('off') | |
| ax = fig.add_subplot(2, 4, 2) | |
| ax.imshow(depth, cmap='gray') | |
| ax.set_title('Depth') | |
| ax.axis('off') | |
| ax = fig.add_subplot(2, 4, 3) | |
| ax.imshow(img_fuse) | |
| ax.set_title('Masks & Bboxes') | |
| ax.axis('off') | |
| ax = fig.add_subplot(2, 4, 4) | |
| ax.imshow(rgb_with_grasp) | |
| ax.set_title('Grasps') | |
| ax.axis('off') | |
| ax = fig.add_subplot(2, 4, 5) | |
| plot = ax.imshow(grasp_masks[0], cmap='jet', vmin=0, vmax=1) | |
| ax.set_title('Quality') | |
| ax.axis('off') | |
| plt.colorbar(plot) | |
| ax = fig.add_subplot(2, 4, 6) | |
| plot = ax.imshow(grasp_masks[1], cmap='jet', vmin=0, vmax=1) | |
| ax.set_title('Quality') | |
| ax.axis('off') | |
| plt.colorbar(plot) | |
| ax = fig.add_subplot(2, 4, 7) | |
| plot = ax.imshow(grasp_masks[2], cmap='rainbow', vmin=-np.pi / 2, vmax=np.pi / 2) | |
| ax.set_title('Angle') | |
| ax.axis('off') | |
| plt.colorbar(plot) | |
| ax = fig.add_subplot(2, 4, 8) | |
| plot = ax.imshow(grasp_masks[3], cmap='jet', vmin=0, vmax=1) | |
| ax.set_title('Width') | |
| ax.axis('off') | |
| plt.colorbar(plot) | |
| plt.suptitle(f"{sentence}", fontsize=20) | |
| plt.tight_layout() | |
| plt.savefig("./visualization.png") | |
| # @functools.lru_cache(maxsize=None) | |
| def _load_bbox(self, bbox): | |
| bbox = bbox.replace("[", "").replace("]", "").split(",") | |
| x, y, w, h = int(bbox[0]), int(bbox[1]), int(bbox[2]), int(bbox[3]) | |
| return [x, y, w, h] | |
| # @functools.lru_cache(maxsize=None) | |
| def _load_rgb(self, path): | |
| image = cv2.imread(os.path.join(self.root_path, path)) | |
| image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) | |
| return image | |
| # @functools.lru_cache(maxsize=None) | |
| def _load_depth(self, path, factor=1000.): | |
| depth = cv2.imread(os.path.join(self.root_path, path), cv2.IMREAD_UNCHANGED) / factor | |
| depth = 1 - (depth / np.max(depth)) | |
| return depth | |
| # @functools.lru_cache(maxsize=None) | |
| def _load_annos(self, path, target_cls): | |
| cls_annos_path = os.path.join(os.path.join(self.root_path, path), str(target_cls)) | |
| file_id = cls_annos_path.split("/")[-2] | |
| cls_annos_path = os.path.join(cls_annos_path, f"{file_id}.txt") | |
| grasps_list = [] | |
| with open(cls_annos_path, 'r') as f: | |
| points_list = [] | |
| for count, line in enumerate(f): | |
| line = line.rstrip() | |
| [x, y] = line.split(' ') | |
| x = float(x) | |
| y = float(y) | |
| pt = (x, y) | |
| points_list.append(pt) | |
| if len(points_list) == 4: | |
| p1, p2, p3, p4 = points_list | |
| center_x = (p1[0] + p3[0]) / 2 | |
| center_y = (p1[1] + p3[1]) / 2 | |
| width = np.sqrt((p1[0] - p4[0]) * (p1[0] - p4[0]) + (p1[1] - p4[1]) * (p1[1] - p4[1])) | |
| height = np.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1])) | |
| # @NOTE | |
| # Along x+ is 0 degree, increase by rotating anti-clockwise | |
| # If you want to use opencv boxPoints & drawContours to visualize grasps | |
| # Remember to take -theta as param :-) | |
| theta = np.arctan2(p4[0] - p1[0], p4[1] - p1[1]) * 180 / np.pi | |
| if theta > 0: | |
| theta = theta-90 | |
| else: | |
| theta = theta+90 | |
| grasps_list.append([center_x, center_y, width, height, theta, int(target_cls)]) | |
| points_list = [] | |
| return grasps_list | |
| # @functools.lru_cache(maxsize=None) | |
| def _load_mask(self, path, target_cls): | |
| masks = cv2.imread(os.path.join(self.root_path, path), cv2.IMREAD_UNCHANGED) | |
| if target_cls == -1: | |
| # for loading instance masks | |
| return masks | |
| else: | |
| # For loading target semantic masks | |
| target_masks = (masks == target_cls) | |
| return target_masks | |
| def _match_masks_with_ref(self, bbox, ins_masks, masks): | |
| # Preparing bounding box for calculating IoU | |
| x1, y1, x2, y2 = bbox | |
| w, h = (x2-x1), (y2-y1) | |
| vertices = [[x1, y1], [x1+w, y1], [x2, y2], [x1, y1+h]] | |
| poly1 = Polygon(vertices) | |
| # Keep only the instance masks with correct class label | |
| ins_masks = ins_masks * masks | |
| ins_props = regionprops(ins_masks) | |
| max_iou = 0.0 | |
| ins_idx = 0 | |
| for ins in ins_props: | |
| _x1, _y1, _x2, _y2 = ins.bbox[1], ins.bbox[0], ins.bbox[3], ins.bbox[2] | |
| _w, _h = (_x2-_x1), (_y2-_y1) | |
| ins_vertices = [[_x1, _y1], [_x1+_w, _y1], [_x2, _y2], [_x1, _y1+_h]] | |
| poly2 = Polygon(ins_vertices) | |
| if poly1.intersects(poly2): | |
| intersect = poly1.intersection(poly2).area | |
| union = poly1.union(poly2).area | |
| iou = intersect/union | |
| if iou > max_iou: | |
| max_iou = iou | |
| ins_idx = ins.label | |
| ins_masks = (ins_masks == ins_idx) | |
| return ins_masks | |
| def _match_grasps_with_ref(self, rects, ins_masks): | |
| # Check if the center of grasp falls in the target instance mask | |
| grasps = [] | |
| for rect in rects: | |
| c_x, c_y = int(rect[0]), int(rect[1]) | |
| if ins_masks[c_y, c_x]: | |
| grasps.append(rect) | |
| return grasps | |
| def _filter_grasps(self, rects): | |
| angles = [] | |
| for rect in rects: | |
| angles.append(rect[4]) | |
| def _generate_grasp_masks(self, grasps, width, height): | |
| pos_out = np.zeros((height, width)) | |
| ang_out = np.zeros((height, width)) | |
| wid_out = np.zeros((height, width)) | |
| for rect in grasps: | |
| center_x, center_y, w_rect, h_rect, theta, cls_id = rect | |
| width_factor = float(100) | |
| # Get 4 corners of rotated rect | |
| # Convert from our angle represent to opencv's | |
| r_rect = ((center_x, center_y), (w_rect/2, h_rect), -(theta+180)) | |
| box = cv2.boxPoints(r_rect) | |
| box = np.int0(box) | |
| rr, cc = polygon(box[:, 0], box[:,1]) | |
| mask_rr = rr < width | |
| rr = rr[mask_rr] | |
| cc = cc[mask_rr] | |
| mask_cc = cc < height | |
| cc = cc[mask_cc] | |
| rr = rr[mask_cc] | |
| pos_out[cc, rr] = 1.0 | |
| if theta < 0: | |
| ang_out[cc, rr] = int(theta + 180) | |
| else: | |
| ang_out[cc, rr] = int(theta) | |
| # Adopt width normalize accoding to class | |
| wid_out[cc, rr] = np.clip(w_rect, 0.0, width_factor) / width_factor | |
| qua_out = (gaussian(pos_out, 3, preserve_range=True) * 255).astype(np.uint8) | |
| pos_out = (pos_out * 255).astype(np.uint8) | |
| ang_out = ang_out.astype(np.uint8) | |
| wid_out = (gaussian(wid_out, 3, preserve_range=True) * 255).astype(np.uint8) | |
| return [pos_out, qua_out, ang_out, wid_out] | |
| def getTransformMat(self, img_size, inverse=False): | |
| ori_h, ori_w = img_size | |
| inp_h, inp_w = self.input_size | |
| scale = min(inp_h / ori_h, inp_w / ori_w) | |
| new_h, new_w = ori_h * scale, ori_w * scale | |
| bias_x, bias_y = (inp_w - new_w) / 2., (inp_h - new_h) / 2. | |
| src = np.array([[0, 0], [ori_w, 0], [0, ori_h]], np.float32) | |
| dst = np.array([[bias_x, bias_y], [new_w + bias_x, bias_y], | |
| [bias_x, new_h + bias_y]], np.float32) | |
| mat = cv2.getAffineTransform(src, dst) | |
| if inverse: | |
| mat_inv = cv2.getAffineTransform(dst, src) | |
| return mat, mat_inv | |
| return mat, None | |
| def getTransformMat(self, img_size, inverse=False): | |
| ori_h, ori_w = img_size | |
| inp_h, inp_w = self.input_size | |
| scale = min(inp_h / ori_h, inp_w / ori_w) | |
| new_h, new_w = ori_h * scale, ori_w * scale | |
| bias_x, bias_y = (inp_w - new_w) / 2., (inp_h - new_h) / 2. | |
| src = np.array([[0, 0], [ori_w, 0], [0, ori_h]], np.float32) | |
| dst = np.array([[bias_x, bias_y], [new_w + bias_x, bias_y], | |
| [bias_x, new_h + bias_y]], np.float32) | |
| mat = cv2.getAffineTransform(src, dst) | |
| if inverse: | |
| mat_inv = cv2.getAffineTransform(dst, src) | |
| return mat, mat_inv | |
| return mat, None | |
| def convert(self, img, mask=None, grasp_quality_mask=None, grasp_sin_masks=None, grasp_cos_masks=None, grasp_width_mask=None): | |
| # Image ToTensor & Normalize | |
| img = torch.from_numpy(img.transpose((2, 0, 1))) | |
| if not isinstance(img, torch.FloatTensor): | |
| img = img.float() | |
| img.div_(255.).sub_(self.mean).div_(self.std) | |
| # Mask ToTensor | |
| if mask is not None: | |
| mask = torch.from_numpy(mask) | |
| if not isinstance(mask, torch.FloatTensor): | |
| mask = mask.float() | |
| if grasp_quality_mask is not None: | |
| grasp_quality_mask = torch.from_numpy(grasp_quality_mask) | |
| if not isinstance(grasp_quality_mask, torch.FloatTensor): | |
| grasp_quality_mask = grasp_quality_mask.float() | |
| if grasp_sin_masks is not None: | |
| grasp_sin_masks = torch.from_numpy(grasp_sin_masks) | |
| if not isinstance(grasp_sin_masks, torch.FloatTensor): | |
| grasp_sin_masks = grasp_sin_masks.float() | |
| if grasp_cos_masks is not None: | |
| grasp_cos_masks = torch.from_numpy(grasp_cos_masks) | |
| if not isinstance(grasp_cos_masks, torch.FloatTensor): | |
| grasp_cos_masks = grasp_cos_masks.float() | |
| if grasp_width_mask is not None: | |
| grasp_width_mask = torch.from_numpy(grasp_width_mask) | |
| if not isinstance(grasp_width_mask, torch.FloatTensor): | |
| grasp_width_mask = grasp_width_mask.float() | |
| return img, mask, grasp_quality_mask, grasp_sin_masks, grasp_cos_masks, grasp_width_mask | |
| def __getitem__(self, index): | |
| data_dict = {} | |
| key = self.keys[index] | |
| ref_data = self.meta_data[key] | |
| obj_cls = int(self.cls_names[ref_data["class"]]) | |
| # Get path to other data | |
| scene_path = ref_data["scene_path"] | |
| depth_path = scene_path.replace("rgb", "depth") | |
| annos_path = scene_path.replace("rgb", "Annotations_per_class")[:-4] | |
| masks_path = scene_path.replace("rgb", "seg_mask_labeled_combi") | |
| ins_masks_path = scene_path.replace("rgb", "seg_mask_instances_combi") | |
| # Read data | |
| rgb = self._load_rgb(scene_path) # [0 - 255] | |
| depth = self._load_depth(depth_path) | |
| annos = self._load_annos(annos_path, obj_cls) | |
| masks = self._load_mask(masks_path, obj_cls) | |
| ins_masks = self._load_mask(ins_masks_path, -1) | |
| bbox = self._load_bbox(ref_data["bbox"]) | |
| sentence = ref_data["sentence"] | |
| # ins_masks = ins_masks * masks | |
| ins_masks = (self._match_masks_with_ref(bbox, ins_masks, masks) * 255).astype(np.uint8) | |
| grasps = self._match_grasps_with_ref(annos, ins_masks) | |
| assert rgb.shape[:2] == depth.shape | |
| height, width = depth.shape | |
| grasp_masks = self._generate_grasp_masks(grasps, width, height) | |
| grasp_quality_masks = grasp_masks[1] | |
| grasp_angle_masks = grasp_masks[2] | |
| grasp_width_masks = grasp_masks[3] | |
| # Image transforms | |
| img_size = rgb.shape[:2] | |
| mat, mat_inv = self.getTransformMat(img_size, True) | |
| rgb = cv2.warpAffine(rgb, | |
| mat, | |
| self.input_size, | |
| flags=cv2.INTER_CUBIC, | |
| borderValue=[0.48145466 * 255, 0.4578275 * 255, 0.40821073 * 255]) | |
| if self.mode == 'train': | |
| ins_masks = cv2.warpAffine(ins_masks, | |
| mat, | |
| self.input_size, | |
| flags=cv2.INTER_LINEAR, | |
| borderValue=0.) | |
| grasp_quality_masks = cv2.warpAffine(grasp_quality_masks, | |
| mat, | |
| self.input_size, | |
| flags=cv2.INTER_LINEAR, | |
| borderValue=0.) | |
| grasp_angle_masks = cv2.warpAffine(grasp_angle_masks, | |
| mat, | |
| self.input_size, | |
| flags=cv2.INTER_LINEAR, | |
| borderValue=0.) | |
| grasp_width_masks = cv2.warpAffine(grasp_width_masks, | |
| mat, | |
| self.input_size, | |
| flags=cv2.INTER_LINEAR, | |
| borderValue=0.) | |
| # Normalize and pre-process target masks | |
| ins_masks = ins_masks / 255. | |
| grasp_quality_masks = grasp_quality_masks / 255. | |
| grasp_angle_masks = grasp_angle_masks * np.pi / 180. | |
| grasp_width_masks = grasp_width_masks / 255. | |
| grasp_sin_masks = np.sin(2 * grasp_angle_masks) | |
| grasp_cos_masks = np.cos(2 * grasp_angle_masks) | |
| word_vec = tokenize(sentence, self.word_length, True).squeeze(0) | |
| # self.visualization(rgb, depth, ins_masks, grasps, (grasp_quality_masks, grasp_sin_masks, grasp_cos_masks, grasp_width_masks), bbox, obj_cls, sentence) | |
| rgb, ins_masks, grasp_quality_masks, grasp_sin_masks, grasp_cos_masks, grasp_width_masks = self.convert( | |
| rgb, ins_masks, grasp_quality_masks, grasp_sin_masks, grasp_cos_masks, grasp_width_masks | |
| ) | |
| # np.savez( | |
| # os.path.join(self.target_save_dir, f"{key}.npz"), | |
| # img=rgb.cpu().numpy(), | |
| # word_vec=word_vec.cpu().numpy(), | |
| # ins_masks=ins_masks.cpu().numpy(), | |
| # grasp_quality_masks=grasp_quality_masks.cpu().numpy(), | |
| # grasp_sin_masks=grasp_sin_masks.cpu().numpy(), | |
| # grasp_cos_masks=grasp_cos_masks.cpu().numpy(), | |
| # grasp_width_masks=grasp_width_masks.cpu().numpy(), | |
| # grasps=grasps | |
| # ) | |
| return rgb, (ins_masks, grasp_quality_masks, grasp_sin_masks, grasp_cos_masks, grasp_width_masks), word_vec | |
| elif self.mode == 'val': | |
| word_vec = tokenize(sentence, self.word_length, True).squeeze(0) | |
| ins_masks = ins_masks / 255. | |
| grasp_quality_masks = grasp_quality_masks / 255. | |
| grasp_angle_masks = grasp_angle_masks * np.pi / 180. | |
| grasp_width_masks = grasp_width_masks / 255. | |
| grasp_sin_masks = np.sin(2 * grasp_angle_masks) | |
| grasp_cos_masks = np.cos(2 * grasp_angle_masks) | |
| rgb = self.convert(rgb)[0] | |
| params = { | |
| # 'mask_dir': mask_dir, | |
| 'inverse': mat_inv, | |
| 'ori_size': np.array(img_size) | |
| } | |
| # np.savez( | |
| # os.path.join(self.target_save_dir, f"{key}.npz"), | |
| # img=rgb.cpu().numpy(), | |
| # word_vec=word_vec.cpu().numpy(), | |
| # ins_masks=ins_masks, | |
| # grasp_quality_masks=grasp_quality_masks, | |
| # grasp_sin_masks=grasp_sin_masks, | |
| # grasp_cos_masks=grasp_cos_masks, | |
| # grasp_width_masks=grasp_width_masks, | |
| # grasps=grasps, | |
| # params=params | |
| # ) | |
| return rgb, (ins_masks, grasp_quality_masks, grasp_sin_masks, grasp_cos_masks, grasp_width_masks), word_vec, params | |
| elif self.mode == 'test': | |
| rgb = self.convert(rgb)[0] | |
| word_vec = tokenize(sentence, self.word_length, True).squeeze(0) | |
| params = { | |
| # 'ori_img': ori_img, | |
| # 'seg_id': seg_id, | |
| # 'mask_dir': mask_dir, | |
| 'inverse': mat_inv, | |
| 'ori_size': np.array(img_size), | |
| 'sents': sentence | |
| } | |
| # np.savez( | |
| # os.path.join(self.target_save_dir, f"{key}.npz"), | |
| # img=rgb.cpu().numpy(), | |
| # word_vec=word_vec.cpu().numpy(), | |
| # params=params | |
| # ) | |
| return rgb, word_vec, params | |
| class GraspTransforms: | |
| # Class for converting cv2-like rectangle formats and generate grasp-quality-angle-width masks | |
| def __init__(self, width_factor=100, width=640, height=480): | |
| self.width_factor = width_factor | |
| self.width = width | |
| self.height = height | |
| def __call__(self, grasp_rectangles, target): | |
| # grasp_rectangles: (M, 4, 2) | |
| M = grasp_rectangles.shape[0] | |
| p1, p2, p3, p4 = np.split(grasp_rectangles, 4, axis=1) | |
| center_x = (p1[..., 0] + p3[..., 0]) / 2 | |
| center_y = (p1[..., 1] + p3[..., 1]) / 2 | |
| width = np.sqrt((p1[..., 0] - p4[..., 0]) * (p1[..., 0] - p4[..., 0]) + (p1[..., 1] - p4[..., 1]) * (p1[..., 1] - p4[..., 1])) | |
| height = np.sqrt((p1[..., 0] - p2[..., 0]) * (p1[..., 0] - p2[..., 0]) + (p1[..., 1] - p2[..., 1]) * (p1[..., 1] - p2[..., 1])) | |
| theta = np.arctan2(p4[..., 0] - p1[..., 0], p4[..., 1] - p1[..., 1]) * 180 / np.pi | |
| theta = np.where(theta > 0, theta - 90, theta + 90) | |
| target = np.tile(np.array([[target]]), (M,1)) | |
| return np.concatenate([center_x, center_y, width, height, theta, target], axis=1) | |
| def inverse(self, grasp_rectangles): | |
| boxes = [] | |
| for rect in grasp_rectangles: | |
| center_x, center_y, width, height, theta = rect[:5] | |
| box = ((center_x, center_y), (width, height), -(theta+180)) | |
| box = cv2.boxPoints(box) | |
| box = np.intp(box) | |
| boxes.append(box) | |
| return boxes | |
| def generate_masks(self, grasp_rectangles): | |
| pos_out = np.zeros((self.height, self.width)) | |
| ang_out = np.zeros((self.height, self.width)) | |
| wid_out = np.zeros((self.height, self.width)) | |
| for rect in grasp_rectangles: | |
| center_x, center_y, w_rect, h_rect, theta = rect[:5] | |
| # Get 4 corners of rotated rect | |
| # Convert from our angle represent to opencv's | |
| r_rect = ((center_x, center_y), (w_rect/2, h_rect), -(theta+180)) | |
| box = cv2.boxPoints(r_rect) | |
| box = np.intp(box) | |
| rr, cc = polygon(box[:, 0], box[:,1]) | |
| mask_rr = rr < self.width | |
| rr = rr[mask_rr] | |
| cc = cc[mask_rr] | |
| mask_cc = cc < self.height | |
| cc = cc[mask_cc] | |
| rr = rr[mask_cc] | |
| pos_out[cc, rr] = 1.0 | |
| if theta < 0: | |
| ang_out[cc, rr] = int(theta + 180) | |
| else: | |
| ang_out[cc, rr] = int(theta) | |
| # Adopt width normalize accoding to class | |
| wid_out[cc, rr] = np.clip(w_rect, 0.0, self.width_factor) / self.width_factor | |
| qua_out = (gaussian(pos_out, 3, preserve_range=True) * 255).astype(np.uint8) | |
| pos_out = (pos_out * 255).astype(np.uint8) | |
| ang_out = ang_out.astype(np.uint8) | |
| wid_out = (gaussian(wid_out, 3, preserve_range=True) * 255).astype(np.uint8) | |
| return {'pos': pos_out, | |
| 'qua': qua_out, | |
| 'ang': ang_out, | |
| 'wid': wid_out} | |
| class OCIDVLGDataset(Dataset): | |
| """ OCID-Vision-Language-Grasping dataset with referring expressions and grasps """ | |
| def __init__(self, | |
| root_dir, | |
| split, | |
| transform_img = None, | |
| transform_grasp = GraspTransforms(), | |
| input_size = 416, | |
| word_length = 20, | |
| with_depth = True, | |
| with_segm_mask = True, | |
| with_grasp_masks = True, | |
| version="multiple" | |
| ): | |
| super(OCIDVLGDataset, self).__init__() | |
| self.root_dir = root_dir | |
| self.split_dir = os.path.join(root_dir, "data_split") | |
| self.split_map = {'train': 'train_expressions.json', | |
| 'val': 'val_expressions.json', | |
| 'test': 'test_expressions.json' | |
| } | |
| self.split = split | |
| self.refer_dir = os.path.join(root_dir, "refer", version) | |
| self.transform_img = transform_img | |
| self.transform_grasp = transform_grasp | |
| self.with_depth = with_depth | |
| self.with_segm_mask = with_segm_mask | |
| self.with_grasp_masks = with_grasp_masks | |
| # assert (self.transform_grasp and self.with_grasp_masks) or (not self.transform_grasp and not self.with_grasp_masks) | |
| self.input_size = (input_size, input_size) | |
| self.word_length = word_length | |
| self.mean = torch.tensor([0.48145466, 0.4578275, | |
| 0.40821073]).reshape(3, 1, 1) | |
| self.std = torch.tensor([0.26862954, 0.26130258, | |
| 0.27577711]).reshape(3, 1, 1) | |
| self._load_dicts() | |
| self._load_split() | |
| def _load_dicts(self): | |
| cwd = os.getcwd() | |
| os.chdir(self.root_dir) | |
| from .OCID_sub_class_dict import cnames, colors, subnames, sub_to_class | |
| cnames_inv = {int(v):k for k,v in cnames.items()} | |
| subnames_inv = {v:k for k,v in subnames.items()} | |
| self.class_names = cnames | |
| self.idx_to_class = cnames_inv | |
| self.class_instance_names = subnames | |
| self.idx_to_class_instance = subnames_inv | |
| self.instance_idx_to_class_idx = sub_to_class | |
| os.chdir(cwd) | |
| def _load_split(self): | |
| refer_data = json.load(open(os.path.join(self.refer_dir, self.split_map[self.split]))) | |
| self.seq_paths, self.img_names, self.scene_ids = [], [], [] | |
| self.bboxes, self.grasps = [], [] | |
| self.sent_to_index, self.sent_indices = {}, [] | |
| self.rgb_paths, self.depth_paths, self.mask_paths = [], [], [] | |
| self.targets, self.sentences, self.semantics, self.objIDs = [], [], [], [] | |
| n = 0 | |
| for item in refer_data['data']: | |
| seq_path, im_name = item['image_filename'].split(',') | |
| self.seq_paths.append(seq_path) | |
| self.img_names.append(im_name) | |
| self.scene_ids.append(item['image_filename']) | |
| self.bboxes.append(item['box']) | |
| self.grasps.append(item['grasps']) | |
| self.objIDs.append(item['answer']) | |
| self.targets.append(item['target']) | |
| self.sentences.append(item['question']) | |
| self.semantics.append(item['program']) | |
| self.rgb_paths.append(os.path.join(seq_path, "rgb", im_name)) | |
| self.depth_paths.append(os.path.join(seq_path, "depth", im_name)) | |
| self.mask_paths.append(os.path.join(seq_path, "seg_mask_instances_combi", im_name)) | |
| self.sent_indices.append(item['question_index']) | |
| self.sent_to_index[item['question_index']] = n | |
| n += 1 | |
| def get_index_from_sent(self, sent_id): | |
| return self.sent_to_index[sent_id] | |
| def get_sent_from_index(self, n): | |
| return self.sent_indices[n] | |
| def _load_sent(self, sent_id): | |
| n = self.get_index_from_sent(sent_id) | |
| scene_id = self.scene_ids[n] | |
| img_path = os.path.join(self.root_dir, self.rgb_paths[n]) | |
| img = self.get_image_from_path(img_path) | |
| x, y, w, h = self.bboxes[n] | |
| bbox = np.asarray([x, y, x+w, y+h]) | |
| sent = self.sentences[n] | |
| target = self.targets[n] | |
| target_idx = self.class_instance_names[target] | |
| objID = self.objIDs[n] | |
| grasps = np.asarray(self.grasps[n]) | |
| result = {'img': self.transform_img(img) if self.transform_img else img, | |
| 'grasps': self.transform_grasp(grasps, target_idx) if self.transform_grasp else None, | |
| 'grasp_rects': self.transform_grasp(grasps, target_idx) if self.transform_grasp else None, | |
| 'sentence': sent, | |
| 'target': target, | |
| 'objID': objID, | |
| 'bbox': bbox, | |
| 'target_idx': target_idx, | |
| 'sent_id': sent_id, | |
| 'scene_id': scene_id, | |
| 'img_path': img_path | |
| } | |
| if self.with_depth: | |
| depth_path = os.path.join(self.root_dir, self.depth_paths[n]) | |
| depth = self.get_depth_from_path(depth_path) | |
| result = {**result, 'depth': torch.from_numpy(depth) if self.transform_img else depth} | |
| if self.with_segm_mask: | |
| mask_path = os.path.join(self.root_dir, self.mask_paths[n]) | |
| msk_full = self.get_mask_from_path(mask_path) | |
| msk = np.where(msk_full == objID, True, False) | |
| result = {**result, 'mask': torch.from_numpy(msk) if self.transform_img else msk} | |
| if self.with_grasp_masks: | |
| grasp_masks = self.transform_grasp.generate_masks(result['grasp_rects']) | |
| result = {**result, 'grasp_masks': grasp_masks} | |
| result = self.preprocess(result) | |
| return result | |
| def get_transform_mat(self, img_size, inverse=False): | |
| ori_h, ori_w = img_size | |
| inp_h, inp_w = self.input_size | |
| scale = min(inp_h / ori_h, inp_w / ori_w) | |
| new_h, new_w = ori_h * scale, ori_w * scale | |
| bias_x, bias_y = (inp_w - new_w) / 2., (inp_h - new_h) / 2. | |
| src = np.array([[0, 0], [ori_w, 0], [0, ori_h]], np.float32) | |
| dst = np.array([[bias_x, bias_y], [new_w + bias_x, bias_y], | |
| [bias_x, new_h + bias_y]], np.float32) | |
| mat = cv2.getAffineTransform(src, dst) | |
| if inverse: | |
| mat_inv = cv2.getAffineTransform(dst, src) | |
| return mat, mat_inv | |
| return mat, None | |
| def preprocess(self, data): | |
| img = data["img"] | |
| sent = data["sentence"] | |
| if np.max(data["mask"]) <= 1.0: | |
| ins_mask = (data["mask"] * 255).astype(np.uint8) | |
| else: | |
| ins_mask = data["mask"] | |
| grasp_qua_mask = data["grasp_masks"]["qua"] | |
| grasp_ang_mask = data["grasp_masks"]["ang"] | |
| grasp_wid_mask = data["grasp_masks"]["wid"] | |
| img_size = img.shape[:2] | |
| mat, mat_inv = self.get_transform_mat(img_size, True) | |
| img = cv2.warpAffine( | |
| img, mat, self.input_size, flags=cv2.INTER_CUBIC, | |
| borderValue=[0.48145466 * 255, 0.4578275 * 255, 0.40821073 * 255] | |
| ) | |
| img = torch.from_numpy(img.transpose((2, 0, 1))) | |
| if not isinstance(img, torch.FloatTensor): | |
| img = img.float() | |
| img.div_(255.).sub_(self.mean).div_(self.std) | |
| ins_mask = cv2.warpAffine(ins_mask, | |
| mat, | |
| self.input_size, | |
| flags=cv2.INTER_LINEAR, | |
| borderValue=0.) | |
| grasp_qua_mask = cv2.warpAffine(grasp_qua_mask, | |
| mat, | |
| self.input_size, | |
| flags=cv2.INTER_LINEAR, | |
| borderValue=0.) | |
| grasp_ang_mask = cv2.warpAffine(grasp_ang_mask, | |
| mat, | |
| self.input_size, | |
| flags=cv2.INTER_LINEAR, | |
| borderValue=0.) | |
| grasp_wid_mask = cv2.warpAffine(grasp_wid_mask, | |
| mat, | |
| self.input_size, | |
| flags=cv2.INTER_LINEAR, | |
| borderValue=0.) | |
| ins_mask = ins_mask / 255. | |
| grasp_qua_mask = grasp_qua_mask / 255. | |
| grasp_ang_mask = grasp_ang_mask * np.pi / 180. | |
| grasp_wid_mask = grasp_wid_mask / 255. | |
| grasp_sin_mask = np.sin(2 * grasp_ang_mask) | |
| grasp_cos_mask = np.cos(2 * grasp_ang_mask) | |
| word_vec = tokenize(sent, self.word_length, True).squeeze(0) | |
| data["img"] = img | |
| data["mask"] = ins_mask | |
| data["grasp_masks"]["qua"] = grasp_qua_mask | |
| data["grasp_masks"]["ang"] = grasp_ang_mask | |
| data["grasp_masks"]["wid"] = grasp_wid_mask | |
| data["grasp_masks"]["sin"] = grasp_sin_mask | |
| data["grasp_masks"]["cos"] = grasp_cos_mask | |
| data["word_vec"] = word_vec | |
| data["sentence"] = sent # Keep the raw sentence | |
| data["inverse"] = mat_inv | |
| data["ori_size"] = np.array(img_size) | |
| # del data["sentence"] | |
| return data | |
| def __len__(self): | |
| return len(self.sent_indices) | |
| def __getitem__(self, n): | |
| sent_id = self.get_sent_from_index(n) | |
| data = self._load_sent(sent_id) | |
| return data | |
| def transform_grasp_inv(grasp_pt): | |
| pass | |
| # @functools.lru_cache(maxsize=None) | |
| def get_image_from_path(self, path): | |
| img_bgr = cv2.imread(path) | |
| if img_bgr is None: | |
| print(os.path.exists(path)) | |
| print(path) | |
| img = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) | |
| return img | |
| # @functools.lru_cache(maxsize=None) | |
| def get_mask_from_path(self, path): | |
| return cv2.imread(path, cv2.IMREAD_UNCHANGED) | |
| # @functools.lru_cache(maxsize=None) | |
| def get_depth_from_path(self, path): | |
| return cv2.imread(path, cv2.IMREAD_UNCHANGED).astype(np.float32) / 1000. # mm -> m | |
| def get_image(self, n): | |
| img_path = os.path.join(self.root_dir, self.imgs[n]) | |
| return self.get_image_from_path(img_path) | |
| def get_annotated_image(self, n, text=True): | |
| sample = self.__getitem__(n) | |
| img, sent, grasps, bbox = sample['img'], sample['sentence'], sample['grasp_rects'], sample['bbox'] | |
| if isinstance(img, torch.FloatTensor): | |
| img = img.permute(1,2,0) | |
| img = (img.cpu().numpy() * 255).astype(np.uint8) | |
| if self.transform_img: | |
| img = np.asarray(tfn.to_pil_image(img)) | |
| if self.transform_grasp: | |
| #grasps = list(map(self.transform_grasp_inv, list(grasps))) | |
| grasps = self.transform_grasp.inverse(grasps) | |
| tmp = img.copy() | |
| for entry in grasps: | |
| ptA, ptB, ptC, ptD = [list(map(int, pt.tolist())) for pt in entry] | |
| tmp = cv2.line(tmp, ptA, ptB, (0,0,0xff), 2) | |
| tmp = cv2.line(tmp, ptD, ptC, (0,0,0xff), 2) | |
| tmp = cv2.line(tmp, ptB, ptC, (0xff,0,0), 2) | |
| tmp = cv2.line(tmp, ptA, ptD, (0xff,0,0), 2) | |
| tmp = cv2.rectangle(tmp, (bbox[0],bbox[1]), (bbox[2],bbox[3]), (0,255,0), 2) | |
| if text: | |
| tmp = cv2.putText(tmp, sent, (0,10), cv2.FONT_HERSHEY_PLAIN, 1, (0,0,0), 2, cv2.LINE_AA) | |
| return tmp | |
| def visualization(self, n, save_path): | |
| s = self.__getitem__(n) | |
| rgb = s['img'] | |
| if isinstance(rgb, torch.FloatTensor): | |
| rgb = rgb.permute(1,2,0) | |
| rgb = (rgb.cpu().numpy() * 255).astype(np.uint8) | |
| depth = (0xff * s['depth'] / 3).astype(np.uint8) | |
| ii = self.get_annotated_image(n, text=False) | |
| sentence = s['sentence'] | |
| msk = s['mask'].astype(np.uint8) / 255 | |
| # msk_img = (rgb * 0.3).astype(np.uint8).copy() | |
| # msk_img[msk, 0] = 255 | |
| fig = plt.figure(figsize=(25, 10)) | |
| ax = fig.add_subplot(2, 4, 1) | |
| ax.imshow(rgb) | |
| ax.set_title('RGB') | |
| ax.axis('off') | |
| ax = fig.add_subplot(2, 4, 2) | |
| ax.imshow(depth, cmap='gray') | |
| ax.set_title('Depth') | |
| ax.axis('off') | |
| ax = fig.add_subplot(2, 4, 3) | |
| ax.imshow(msk) | |
| ax.set_title('Segm Mask') | |
| ax.axis('off') | |
| ax = fig.add_subplot(2, 4, 4) | |
| ax.imshow(ii) | |
| ax.set_title('Box & Grasp') | |
| ax.axis('off') | |
| ax = fig.add_subplot(2, 4, 5) | |
| plot = ax.imshow(s['grasp_masks']['qua'], cmap='jet', vmin=0, vmax=1) | |
| ax.set_title('Grasp quality') | |
| ax.axis('off') | |
| plt.colorbar(plot) | |
| ax = fig.add_subplot(2, 4, 6) | |
| plot = ax.imshow(s['grasp_masks']['sin'], cmap='rainbow', vmin=-1, vmax=1) | |
| ax.set_title('Angle-cosine') | |
| ax.axis('off') | |
| plt.colorbar(plot) | |
| ax = fig.add_subplot(2, 4, 7) | |
| plot = ax.imshow(s['grasp_masks']['cos'], cmap='rainbow', vmin=-1, vmax=1) | |
| ax.set_title('Angle-sine') | |
| ax.axis('off') | |
| plt.colorbar(plot) | |
| ax = fig.add_subplot(2, 4, 8) | |
| plot = ax.imshow(s['grasp_masks']['wid'], cmap='jet', vmin=0, vmax=1) | |
| ax.set_title('Width') | |
| ax.axis('off') | |
| plt.colorbar(plot) | |
| plt.suptitle(f"{sentence}", fontsize=20) | |
| plt.tight_layout() | |
| print("save") | |
| plt.savefig(os.path.join(save_path, f"sample_{n}.png")) | |
| def collate_fn(batch): | |
| return { | |
| "img": torch.stack([x["img"] for x in batch]), | |
| "depth": torch.stack([torch.from_numpy(x["depth"]).float() for x in batch]), | |
| "mask": torch.stack([torch.from_numpy(x["mask"]).float() for x in batch]), | |
| "grasp_masks" : { | |
| "qua": torch.stack([torch.from_numpy(x["grasp_masks"]["qua"]).float() for x in batch]), | |
| "sin": torch.stack([torch.from_numpy(x["grasp_masks"]["sin"]).float() for x in batch]), | |
| "cos": torch.stack([torch.from_numpy(x["grasp_masks"]["cos"]).float() for x in batch]), | |
| "wid": torch.stack([torch.from_numpy(x["grasp_masks"]["wid"]).float() for x in batch]) | |
| }, | |
| "word_vec": torch.stack([x["word_vec"].long() for x in batch]), | |
| "grasps": [x["grasps"] for x in batch], | |
| "target": [x["target"] for x in batch], | |
| "sentence": [x["sentence"] for x in batch], | |
| "bbox": [x["bbox"] for x in batch], | |
| "target_idx": [x["target_idx"] for x in batch], | |
| "sent_id": [x["sent_id"] for x in batch], | |
| "scene_id": [x["scene_id"] for x in batch], | |
| "inverse": [x["inverse"] for x in batch], | |
| "ori_size": [x["ori_size"] for x in batch], | |
| "img_path": [x["img_path"] for x in batch] | |
| } | |
| class OCIDGraspDataset(Dataset): | |
| """ OCID-Grasp dataset """ | |
| def __init__(self, | |
| cfg, | |
| split): | |
| self.cfg = cfg | |
| self.split = split | |
| self.root_dir = cfg.root_dir | |
| self.img_size = cfg.img_size | |
| self.depth_factor = cfg.depth_factor | |
| self.with_grasp_masks = cfg.with_grasp_masks | |
| self.with_sem_masks = cfg.with_sem_masks | |
| self.with_ins_masks = cfg.with_ins_masks | |
| self.with_depth = cfg.with_depth | |
| self.grasp_transforms = GraspTransforms() | |
| aug_mode = "train" if self.split == "training_0" else "test" | |
| self.data_augmentor = DataAugmentor(cfg, mode=aug_mode) | |
| # self.data_augmentor = DataAugmentor(cfg) | |
| self._load_dicts() | |
| self.num_classes = len(cnames) | |
| with open(os.path.join(cfg.root_dir, "data_split", split + ".txt"), "r") as fid: | |
| self.meta = [x.strip().split(',') for x in fid.readlines()] | |
| def _load_dicts(self): | |
| cwd = os.getcwd() | |
| os.chdir(self.root_dir) | |
| from .OCID_sub_class_dict import cnames, colors, subnames, sub_to_class | |
| cnames_inv = {int(v):k for k,v in cnames.items()} | |
| subnames_inv = {v:k for k,v in subnames.items()} | |
| self.class_names = cnames | |
| self.idx_to_class = cnames_inv | |
| self.class_instance_names = subnames | |
| self.idx_to_class_instance = subnames_inv | |
| self.instance_idx_to_class_idx = sub_to_class | |
| os.chdir(cwd) | |
| def _get_rgb_image(self, scene_id, img_f, data_dict): | |
| img_path = os.path.join(self.root_dir, scene_id, "rgb", img_f) | |
| img = cv2.imread(img_path, cv2.COLOR_BGR2RGB) | |
| data_dict["rgb"] = img | |
| def _get_depth_image(self, scene_id, img_f, data_dict): | |
| depth_path = os.path.join(self.root_dir, scene_id, "depth", img_f) | |
| depth = cv2.imread(depth_path, cv2.IMREAD_UNCHANGED) / float(self.depth_factor) | |
| depth = 1 - (depth / np.max(depth)) | |
| data_dict["depth"] = depth | |
| def _get_sem_mask(self, scene_id, img_f, data_dict): | |
| sem_mask = cv2.imread(os.path.join(self.root_dir, scene_id, "seg_mask_labeled_combi", img_f), cv2.IMREAD_UNCHANGED) | |
| data_dict["sem_mask"] = sem_mask | |
| return sem_mask | |
| def _get_ins_mask(self, scene_id, img_f, data_dict): | |
| # Load semantic mask first if the with_sem_masks set to False | |
| if "sem_mask" not in data_dict.keys(): | |
| sem_mask = cv2.imread(os.path.join(self.root_dir, scene_id, "seg_mask_labeled_combi", img_f), cv2.IMREAD_UNCHANGED) | |
| else: | |
| sem_mask = data_dict["sem_mask"] | |
| ins_mask = cv2.imread(os.path.join(self.root_dir, scene_id, "seg_mask_instances_combi", img_f), cv2.IMREAD_UNCHANGED) | |
| labels = [] | |
| bboxes = [] | |
| ins_masks = [] | |
| props = regionprops(sem_mask) | |
| for prop in props: | |
| cls_id = prop.label | |
| # Get binary mask for each semantic class | |
| bin_mask = (sem_mask == cls_id).astype('int8') | |
| # Get corresponding semantic mask (may contains multiple instances) | |
| cls_ins_mask = (ins_mask * bin_mask) | |
| # Get regions for each instance | |
| ins_props = regionprops(cls_ins_mask) | |
| for ins in ins_props: | |
| labels.append(cls_id) | |
| bboxes.append([ins.bbox[1], ins.bbox[0], ins.bbox[3], ins.bbox[2], cls_id]) | |
| mask = (cls_ins_mask == ins.label).astype('int8').astype('float32') | |
| ins_masks.append(mask) | |
| bboxes = np.array(bboxes).astype('float32') | |
| labels = np.array(labels) | |
| ins_masks = np.array(ins_masks) | |
| data_dict["bboxes"] = bboxes | |
| data_dict["labels"] = labels | |
| data_dict["ins_masks"] = ins_masks | |
| def _get_per_cls_grasp_rects(self, scene_id, img_f, data_dict): | |
| anno_path = os.path.join(self.root_dir, scene_id, "Annotations_per_class", img_f[:-4]) | |
| grasps_list = [] | |
| for cls_id in os.listdir(anno_path): | |
| grasp_path = os.path.join(anno_path, cls_id, img_f[:-4]+".txt") | |
| with open(grasp_path, 'r') as f: | |
| points_list = [] | |
| for count, line in enumerate(f): | |
| line = line.rstrip() | |
| [x, y] = line.split(' ') | |
| x = float(x) | |
| y = float(y) | |
| pt = (x, y) | |
| points_list.append(pt) | |
| if len(points_list) == 4: | |
| p1, p2, p3, p4 = points_list | |
| center_x = (p1[0] + p3[0]) / 2 | |
| center_y = (p1[1] + p3[1]) / 2 | |
| width = np.sqrt((p1[0] - p4[0]) * (p1[0] - p4[0]) + (p1[1] - p4[1]) * (p1[1] - p4[1])) | |
| height = np.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1])) | |
| # @NOTE | |
| # Along x+ is 0 degree, increase by rotating anti-clockwise | |
| # If you want to use opencv boxPoints & drawContours to visualize grasps | |
| # Remember to take -theta as param :-) | |
| theta = np.arctan2(p4[0] - p1[0], p4[1] - p1[1]) * 180 / np.pi | |
| if theta > 0: | |
| theta = theta-90 | |
| else: | |
| theta = theta+90 | |
| grasps_list.append([center_x, center_y, width, height, theta, int(cls_id)]) | |
| points_list = [] | |
| data_dict["raw_grasp_rects"] = grasps_list | |
| def _get_grasp_mask(self, scene_id, img_f, data_dict): | |
| grasp_rects = data_dict["raw_grasp_rects"] | |
| data_dict["grasp_masks"] = {} | |
| bboxes = data_dict["bboxes"] | |
| labels = data_dict["labels"] | |
| masks = data_dict["ins_masks"] # @NOTE there may exist instance with no grasp annotations, thus we need to filter them out | |
| assert bboxes.shape[0] == masks.shape[0], "inconsistent bounding boxes and instances, check the data" | |
| num_ins = bboxes.shape[0] | |
| ins_grasp_rects = [] | |
| ins_grasp_masks = [] | |
| ins_bboxes = [] | |
| ins_masks = [] | |
| ins_labels = [] | |
| for i in range(num_ins): | |
| box = bboxes[i] | |
| mask = masks[i] | |
| label = labels[i] | |
| tmp = [] | |
| for rect in grasp_rects: | |
| center_x, center_y, w, h = rect[:4] | |
| cls_id = rect[-1] | |
| # Grasp rect and bbox should have the same cls_id | |
| if int(cls_id) == int(box[4]): | |
| # Center of grasp rect in bbox | |
| if mask[int(center_y), int(center_x)]: | |
| tmp.append(rect) | |
| if len(tmp) > 0: | |
| ins_grasp_masks.append(self.grasp_transforms.generate_masks(tmp)) | |
| ins_grasp_rects.append(tmp) | |
| ins_bboxes.append(box) | |
| ins_masks.append(mask) | |
| ins_labels.append(label) | |
| data_dict["bboxes"] = np.asarray(ins_bboxes) | |
| data_dict["labels"] = np.asarray(ins_labels) | |
| data_dict["ins_masks"] = np.asarray(ins_masks) | |
| data_dict["ins_grasp_rects"] = ins_grasp_rects | |
| data_dict["grasp_masks"]["qua"] = np.asarray([gm["qua"] / 255 for gm in ins_grasp_masks]) | |
| data_dict["grasp_masks"]["ang"] = np.asarray([gm["ang"] for gm in ins_grasp_masks]) | |
| data_dict["grasp_masks"]["wid"] = np.asarray([gm["wid"] / 255 for gm in ins_grasp_masks]) | |
| def __len__(self): | |
| return len(self.meta) | |
| def __getitem__(self, index): | |
| data_dict = {} | |
| scene_id, img_f = self.meta[index] | |
| data_dict["scene_id"] = scene_id | |
| data_dict["img_f"] = img_f | |
| img_path = os.path.join(self.root_dir, scene_id, "rgb", img_f) | |
| img = cv2.imread(img_path) | |
| data_dict["rgb"] = img | |
| data_dict["ori_size"] = img.shape[:2] | |
| if self.with_depth: | |
| self._get_depth_image(scene_id, img_f, data_dict) | |
| if self.with_sem_masks: | |
| self._get_sem_mask(scene_id, img_f, data_dict) | |
| if self.with_ins_masks: | |
| self._get_ins_mask(scene_id, img_f, data_dict) | |
| if self.with_grasp_masks: | |
| self._get_per_cls_grasp_rects(scene_id, img_f, data_dict) | |
| self._get_grasp_mask(scene_id, img_f, data_dict) | |
| self.data_augmentor(data_dict) | |
| data_dict["grasp_masks"]["sin"] = np.sin(2 * data_dict["grasp_masks"]["ang"]) | |
| data_dict["grasp_masks"]["cos"] = np.cos(2 * data_dict["grasp_masks"]["ang"]) | |
| return data_dict | |
| def visualization(self, index, tgt_dir, with_preprocessing=False): | |
| data_dict = {} | |
| scene_id, img_f = self.meta[index] | |
| data_dict["scene_id"] = scene_id | |
| data_dict["img_f"] = img_f | |
| img_path = os.path.join(self.root_dir, scene_id, "rgb", img_f) | |
| img = cv2.imread(img_path, cv2.COLOR_BGR2RGB) | |
| data_dict["rgb"] = img | |
| if self.with_depth: | |
| self._get_depth_image(scene_id, img_f, data_dict) | |
| if self.with_sem_masks: | |
| self._get_sem_mask(scene_id, img_f, data_dict) | |
| if self.with_ins_masks: | |
| self._get_ins_mask(scene_id, img_f, data_dict) | |
| if self.with_grasp_masks: | |
| self._get_per_cls_grasp_rects(scene_id, img_f, data_dict) | |
| self._get_grasp_mask(scene_id, img_f, data_dict) | |
| if with_preprocessing: | |
| self.data_augmentor(data_dict) | |
| img = data_dict["rgb"].transpose((1,2,0)) | |
| # img = img / 255. | |
| num_ins = data_dict["bboxes"].shape[0] | |
| fig = plt.figure(figsize=(25, 10)) | |
| ax = fig.add_subplot(2, 4, 1) | |
| ax.imshow(np.clip(img[:, :, ::-1], 0.0, 1.0)*255) | |
| ax.set_title('RGB') | |
| ax.axis('off') | |
| ax = fig.add_subplot(2, 4, 2) | |
| ax.imshow(data_dict["depth"], cmap='gray') | |
| ax.set_title('Depth') | |
| ax.axis('off') | |
| ax = fig.add_subplot(2, 4, 3) | |
| ax.imshow(data_dict["sem_mask"]) | |
| ax.set_title('Segm Mask') | |
| ax.axis('off') | |
| plt.tight_layout() | |
| plt.savefig(os.path.join(tgt_dir, f"raw-data.png")) | |
| plt.clf() | |
| plt.cla() | |
| plt.close() | |
| for i in range(num_ins): | |
| fig = plt.figure(figsize=(20, 2)) | |
| ins_box = data_dict["bboxes"][i] | |
| ins_mask = data_dict["ins_masks"][i] | |
| ins_label = self.idx_to_class[data_dict["labels"][i]] | |
| ins_grasp_rects = data_dict["ins_grasp_rects"][i] | |
| ins_grasp_qua_masks = data_dict["grasp_masks"]["qua"][i] | |
| ins_grasp_ang_masks = data_dict["grasp_masks"]["ang"][i] | |
| ins_grasp_wid_masks = data_dict["grasp_masks"]["wid"][i] | |
| grasps = self.grasp_transforms.inverse(ins_grasp_rects) | |
| tmp = img.copy() | |
| h, w, c = tmp.shape | |
| for entry in grasps: | |
| ptA, ptB, ptC, ptD = [list(map(int, pt.tolist())) for pt in entry] | |
| tmp = cv2.line(tmp, ptA, ptB, (0,0,0xff), 2) | |
| tmp = cv2.line(tmp, ptD, ptC, (0,0,0xff), 2) | |
| tmp = cv2.line(tmp, ptB, ptC, (0xff,0,0), 2) | |
| tmp = cv2.line(tmp, ptA, ptD, (0xff,0,0), 2) | |
| if ins_box[0] <= 1: | |
| tmp = cv2.rectangle(tmp, (int(ins_box[0]*w),int(ins_box[1]*h)), (int(ins_box[2]*w),int(ins_box[3]*h)), (0,0,0xff), 2) | |
| else: | |
| tmp = cv2.rectangle(tmp, (int(ins_box[0]),int(ins_box[1])), (int(ins_box[2]),int(ins_box[3])), (0,0,0xff), 2) | |
| ax = fig.add_subplot(1, 5, 1) | |
| ax.imshow(tmp[:, :, ::-1]) | |
| ax.set_title('Bboxes & Grasps') | |
| ax.axis('off') | |
| ax = fig.add_subplot(1, 5, 2) | |
| tmp_mask = np.expand_dims(ins_mask, axis=-1).repeat(3, axis=-1) | |
| ax.imshow(tmp_mask*0.6 + tmp[:, :, ::-1] *0.4) | |
| ax.set_title('ins mask') | |
| ax.axis('off') | |
| ax = fig.add_subplot(1, 5, 3) | |
| plot = ax.imshow(ins_grasp_qua_masks, cmap='jet', vmin=0, vmax=1) | |
| ax.set_title('Grasp quality') | |
| ax.axis('off') | |
| plt.colorbar(plot) | |
| ax = fig.add_subplot(1, 5, 4) | |
| plot = ax.imshow(ins_grasp_ang_masks, cmap='rainbow', vmin=-1, vmax=1) | |
| ax.set_title('Grasp angle') | |
| ax.axis('off') | |
| plt.colorbar(plot) | |
| ax = fig.add_subplot(1, 5, 5) | |
| plot = ax.imshow(ins_grasp_wid_masks, cmap='rainbow', vmin=0, vmax=1) | |
| ax.set_title('Grasp width') | |
| ax.axis('off') | |
| plt.colorbar(plot) | |
| plt.tight_layout() | |
| plt.savefig(os.path.join(tgt_dir, f"ins-{i}-{ins_label}.png")) | |
| def collate_fn(batch): | |
| return { | |
| "scene_id": [x["scene_id"] for x in batch], | |
| "img_f": [x["img_f"] for x in batch], | |
| "ori_size": batch[0]["ori_size"], | |
| "rgb": torch.stack([torch.from_numpy(x["rgb"]) for x in batch]), | |
| "depth": torch.stack([torch.from_numpy(x["depth"]) for x in batch]).unsqueeze(1), | |
| "labels": [torch.from_numpy(x["labels"]).long() for x in batch], | |
| "bboxes": [torch.from_numpy(x["bboxes"]) for x in batch], | |
| "ins_masks": [torch.from_numpy(x["ins_masks"]).float() for x in batch], | |
| "sem_mask": torch.stack([torch.from_numpy(x["sem_mask"]).float() for x in batch]), | |
| "grasp_rects": [x["ins_grasp_rects"] for x in batch], | |
| "grasp_masks" : { | |
| "qua": [torch.from_numpy(x["grasp_masks"]["qua"]).float() for x in batch], | |
| "sin": [torch.from_numpy(x["grasp_masks"]["sin"]).float() for x in batch], | |
| "cos": [torch.from_numpy(x["grasp_masks"]["cos"]).float() for x in batch], | |
| "wid": [torch.from_numpy(x["grasp_masks"]["wid"]).float() for x in batch] | |
| }, | |
| } | |