Skip to content

Commit 177936f

Browse files
committed
upload nocs evaluation code
1 parent ab7e882 commit 177936f

File tree

5 files changed

+66
-16
lines changed

5 files changed

+66
-16
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
checkpoints/
2-
**/__pycache__
2+
**/__pycache__
3+
data/nocs*

README.md

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ CVPR 2022
2020
<a href='https://qq456cvb.github.io/projects/cppf'>
2121
<img src='https://img.shields.io/badge/Project-Page-green?style=flat&logo=googlechrome&logoColor=green' alt='Project Page'>
2222
</a>
23-
<a href='https://colab.research.google.com/'>
23+
<a href='#'>
2424
<img src='https://colab.research.google.com/assets/colab-badge.svg' alt='Google Colab'>
2525
</a>
2626
<br>
@@ -86,24 +86,62 @@ python train.py category=bathtub,bed,bookshelf,chair,sofa,table -m
8686

8787
For Laptops, geometry alone cannot determine the pose unambiguously, we rely on an auxiliary segmentation network that segments out the lid and the keyboard base.
8888

89-
To train the segmenter network, first download our Blender physically rendered laptop images from [Google Drive]() and place it under ``data/laptop``. Then run the following command:
89+
To train the segmenter network, first download our Blender physically rendered laptop images from [Google Drive](https://drive.google.com/file/d/1gRHGt47nP9arDAu3hwnDNgfwJMxJYtCa/view?usp=sharing) and place it under ``data/laptop``. Then run the following command:
9090
```
9191
python train_laptop_aux.py
9292
```
9393
</details>
9494

9595

9696
# Pretrained Models
97+
Pretrained models for various ShapeNet categories can be downloaded from [Google Drive](https://drive.google.com/drive/folders/11wm5WHDjmSBfhng6emxCBBYZexmLoxLk?usp=sharing).
9798
# Test on NOCS REAL275
9899

99100
<details>
100-
<summary>With Instance Segmentation Mask</summary>
101+
<summary>Data Preparation</summary>
102+
103+
First download the detection priors from [Google Drive](https://drive.google.com/file/d/1cvGiXG_2ya8CMHss1IDobdL81qeODOrE/view?usp=sharing), which is used for evaluation with instance segmentation or bounding box masks. Put the directory under ``data/nocs_seg``.
104+
105+
Then download RGB-D images from [NOCS REAL275](http://download.cs.stanford.edu/orion/nocs/real_test.zip) dataset and put it under ``data/nocs``.
101106

107+
Place (pre-)trained models under ``checkpoints``.
102108
</details>
103109

104-
## With Bounding Box Mask
110+
<details>
111+
<summary>Evaluate with Instance Segmentation Mask</summary>
112+
113+
First save inference outputs:
114+
```
115+
python nocs/inference.py
116+
```
105117

106-
## Zero-Shot Instance Segmentation and Pose Estimation
118+
Then evaluate mAP:
119+
```
120+
python nocs/eval.py | tee nocs/map.txt
121+
```
122+
</details>
123+
124+
<details>
125+
<summary> Evaluate with Bounding Box Mask</summary>
126+
127+
First save inference outputs with bounding box mask enabled:
128+
```
129+
python nocs/inference.py --bbox_mask
130+
```
131+
132+
Then evaluate mAP:
133+
```
134+
python nocs/eval.py | tee nocs/map_bbox.txt
135+
```
136+
</details>
137+
138+
<details>
139+
<summary> Zero-Shot Instance Segmentation and Pose Estimation</summary>
140+
Coming soon.
141+
142+
</details>
107143
# Test on SUN RGB-D
144+
Coming soon.
108145

109-
# Train on Your Own Object Collections
146+
# Train on Your Own Object Collections
147+
Coming soon.

nocs/eval.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
else:
2828
assert len(result['gt_handle_visibility']) == len(result['gt_class_ids']), "{} {}".format(result['gt_handle_visibility'], result['gt_class_ids'])
2929

30-
3130
if type(result) is list:
3231
final_results += result
3332
elif type(result) is dict:

nocs/inference.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@
3131
if __name__ == "__main__":
3232
parser = argparse.ArgumentParser()
3333
parser.add_argument('--seg_dir', default='data/nocs_seg', help='Segmentation PKL files for NOCS')
34+
parser.add_argument('--nocs_dir', default='data/nocs', help='NOCS real test image path')
3435
parser.add_argument('--out_dir', default='data/nocs_prediction', help='Output directory for predictions')
3536
parser.add_argument('--cp_device', type=int, default=0, help='GPU device number for custom voting algorithms')
3637
parser.add_argument('--ckpt_path', default='checkpoints', help='Model checkpoint path')
3738
parser.add_argument('--angle_prec', type=float, default=1.5, help='Angle precision in orientation voting')
3839
parser.add_argument('--num_rots', type=int, default=72, help='Number of candidate center votes generated for a given point pair')
40+
parser.add_argument('--bbox_mask', action='store_true', help='Whether to use bbox mask instead of instance segmentations.')
3941
args = parser.parse_args()
4042

4143
cp_device = args.cp_device
@@ -102,16 +104,19 @@
102104
bcelogits = torch.nn.BCEWithLogitsLoss()
103105

104106
for res in tqdm(final_results):
105-
img = cv2.imread(res['image_path'] + '_color.png')[:, :, ::-1]
106-
depth = cv2.imread(res['image_path'] + '_depth.png', -1)
107+
img = cv2.imread(os.path.join(args.nocs_dir, res['image_path'][5:] + '_color.png'))[:, :, ::-1]
108+
depth = cv2.imread(os.path.join(args.nocs_dir, res['image_path'][5:] + '_depth.png'), -1)
107109

108110
bboxs = res['pred_bboxes']
109-
masks = res['pred_masks']
111+
masks = res['pred_masks'].copy()
110112
RTs = np.zeros((len(bboxs), 4, 4), dtype=np.float32)
111113
scales = np.zeros((len(bboxs), 3), dtype=np.float32)
112114
cls_ids = res['pred_class_ids']
113115

114116
for i, bbox in enumerate(bboxs):
117+
if args.bbox_mask:
118+
masks[:, :, i][bbox[0]:bbox[2], bbox[1]:bbox[3]] = True
119+
115120
cls_id = cls_ids[i]
116121
cls_name = synset_names[cls_id]
117122

@@ -297,10 +302,10 @@
297302
if cfg.regress_right:
298303
right = final_directions[1]
299304
right -= np.dot(up, right) * up
300-
right /= np.linalg.norm(right)
305+
right /= (np.linalg.norm(right) + 1e-9)
301306
else:
302307
right = np.array([0, -up[2], up[1]])
303-
right /= np.linalg.norm(right)
308+
right /= (np.linalg.norm(right) + 1e-9)
304309

305310
if (cls_name == 'laptop') and (laptop_up is not None):
306311
if np.dot(up, laptop_up) + np.dot(right, laptop_up) < np.dot(up, -laptop_up) + np.dot(right, -laptop_up):
@@ -311,16 +316,23 @@
311316
right = up
312317
up = laptop_up
313318
right -= np.dot(up, right) * up
314-
right /= np.linalg.norm(right)
315-
319+
right /= (np.linalg.norm(right) + 1e-9)
320+
321+
if np.linalg.norm(right) < 1e-7: # right is zero
322+
right = np.random.randn(3)
323+
right -= right.dot(up) * up
324+
right /= np.linalg.norm(right)
325+
316326
if cfg.z_right:
317327
R_est = np.stack([np.cross(up, right), up, right], -1)
318328
else:
319329
R_est = np.stack([right, up, np.cross(right, up)], -1)
320330

321331
pred_scale = np.exp(preds_scale[0].mean(0).cpu().numpy()) * cfg.scale_mean * 2
322332
scale_norm = np.linalg.norm(pred_scale)
333+
assert scale_norm > 0
323334
RTs[i][:3, :3] = R_est * scale_norm
335+
RTs[i][3, 3] = 1.
324336
scales[i, :] = pred_scale / scale_norm
325337

326338
res['pred_RTs'] = RTs

utils/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ def compute_degree_cm_mAP(final_results, synset_names, log_dir, degree_threshold
799799
pred_bboxes[...] = 1
800800
if len(pred_RTs) > 0:
801801
norm_pred_scales = np.stack([np.cbrt(np.linalg.det(pred_RT[:3, :3])) for pred_RT in pred_RTs])
802-
pred_RTs[:, :3, :3] = pred_RTs[:, :3, :3] / norm_pred_scales[:, None, None]
802+
pred_RTs[:, :3, :3] = pred_RTs[:, :3, :3] / (norm_pred_scales[:, None, None] + 1e-9)
803803
pred_scales = pred_scales * norm_pred_scales[:, None]
804804
#print(pred_bboxes.shape[0], pred_class_ids.shape[0], pred_scores.shape[0], pred_RTs.shape[0])
805805

0 commit comments

Comments
 (0)