Skip to content

Commit 883825a

Browse files
committed
nyuv2 extraction tools
1 parent b92d15c commit 883825a

13 files changed

+388
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
NYUv2
2+
colored_*
3+
test_labels_13
4+
train_labels_13
5+
*.zip
6+
*.mat

README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,58 @@
1+
# NYUv2 Python Toolkits
2+
3+
<div>
4+
<img src="test/image.png" width="18%">
5+
<img src="test/semantic13.png" width="18%">
6+
<img src="test/semantic40.png" width="18%">
7+
<img src="test/depth.png" width="18%">
8+
<img src="test/normal.png" width="18%">
9+
</div>
10+
11+
This repo provides extraction tools and a pytorch dataloader written in python for NYUv2 dataset. All meta data comes from [ankurhanda/nyuv2-meta-data](https://github.com/ankurhanda/nyuv2-meta-data)
12+
13+
Supported Tasks:
14+
15+
* Semantic Segmentation (13 classes and 40 classes)
16+
* Depth Estimation
17+
* Normal
18+
19+
## Extraction
20+
21+
```bash
22+
bash download_and_extract.sh
23+
```
24+
or
25+
26+
```bash
27+
wget http://horatio.cs.nyu.edu/mit/silberman/nyu_depth_v2/nyu_depth_v2_labeled.mat
28+
wget https://inf.ethz.ch/personal/ladickyl/nyu_normals_gt.zip
29+
30+
python extract_nyuv2.py --mat nyu_depth_v2_labeled.mat --normal_zip nyu_normals_gt.zip --data_root NYUv2 --save_colored
31+
```
32+
All images and labels will be extracted to ./NYUv2 as the following:
33+
34+
```
35+
NYUv2/
36+
/image
37+
/train
38+
00003.png
39+
00004.png
40+
...
41+
/test
42+
/seg13
43+
/train
44+
00003.png
45+
00004.png
46+
...
47+
/test
48+
/seg40
49+
/depth
50+
/normal
51+
```
52+
53+
54+
# nyuv2-meta-data
55+
156
## What does this repository contain?
257

358
This repository contains 13 class labels for both train and test dataset in NYUv2. This is to avoid any hassle involved in parsing the data from the .mat files. If you are looking to train a network to do 13 class segmentation from RGB data, then this repository can provide you both the training/test dataset as well the corresponding ground truth labels. However, if your networks needs additionally depth data (either depth image or DHA features) then you will need to download the dataset from the [NYUv2 website](http://horatio.cs.nyu.edu/mit/silberman/nyu_depth_v2/nyu_depth_v2_labeled.mat) (~2.8GB) as well as the corresponding [toolbox](http://cs.nyu.edu/~silberman/code/toolbox_nyu_depth_v2.zip). To summarise, this repository contains the following

download_and_extract.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
wget http://horatio.cs.nyu.edu/mit/silberman/nyu_depth_v2/nyu_depth_v2_labeled.mat
2+
wget https://inf.ethz.ch/personal/ladickyl/nyu_normals_gt.zip
3+
4+
python extract_nyuv2.py --mat nyu_depth_v2_labeled.mat --normal_zip nyu_normals_gt.zip --data_root NYUv2 --save_colored

extract_nyuv2.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import os
2+
import sys
3+
import cv2
4+
import h5py
5+
import argparse
6+
import multiprocessing
7+
import numpy as np
8+
from skimage import io
9+
from scipy.io import loadmat
10+
from tqdm import tqdm
11+
import shutil
12+
import matplotlib
13+
import matplotlib.pyplot as plt
14+
import zipfile
15+
16+
17+
def colormap(N=256, normalized=False):
18+
def bitget(byteval, idx):
19+
return ((byteval & (1 << idx)) != 0)
20+
21+
dtype = 'float32' if normalized else 'uint8'
22+
cmap = np.zeros((N, 3), dtype=dtype)
23+
for i in range(N):
24+
r = g = b = 0
25+
c = i
26+
for j in range(8):
27+
r = r | (bitget(c, 0) << 7-j)
28+
g = g | (bitget(c, 1) << 7-j)
29+
b = b | (bitget(c, 2) << 7-j)
30+
c = c >> 3
31+
32+
cmap[i] = np.array([r, g, b])
33+
34+
cmap = cmap/255 if normalized else cmap
35+
return cmap
36+
37+
38+
def extract_images(imgs, splits, IMAGE_DIR):
39+
print("Extracting images...")
40+
imgs = imgs.transpose(0, 3, 2, 1)
41+
for s in ['train', 'test']:
42+
os.makedirs(os.path.join(IMAGE_DIR, s), exist_ok=True)
43+
idxs = splits[s+'Ndxs'].reshape(-1)
44+
for idx in tqdm(idxs):
45+
img = imgs[idx-1]
46+
path = os.path.join(IMAGE_DIR, s, '%05d.png' % (idx))
47+
io.imsave(path, img)
48+
49+
50+
def extract_labels(labels, splits, SEG40_DIR, SEG13_DIR, save_colored=True):
51+
mapping40 = loadmat('classMapping40.mat')['mapClass'][0]
52+
mapping13 = loadmat('class13Mapping.mat')['classMapping13'][0][0][0][0]
53+
mapping40 = np.insert(mapping40, 0, 0)
54+
mapping13 = np.insert(mapping13, 0, 0)
55+
labels = labels.transpose([0, 2, 1])
56+
57+
labels_40 = mapping40[labels]
58+
labels_13 = mapping13[labels_40]
59+
60+
if save_colored:
61+
cmap = colormap()
62+
os.makedirs('colored_40', exist_ok=True)
63+
os.makedirs('colored_13', exist_ok=True)
64+
65+
print("Extracting labels (40 classes)...")
66+
67+
for s in ['train', 'test']:
68+
os.makedirs(os.path.join(SEG40_DIR, s), exist_ok=True)
69+
idxs = splits[s+'Ndxs'].reshape(-1)
70+
71+
for idx in tqdm(idxs):
72+
lbl = labels_40[idx-1]
73+
path = os.path.join(SEG40_DIR, s, '%05d.png' % (idx))
74+
io.imsave(path, lbl, check_contrast=False)
75+
if save_colored:
76+
colored_lbl = cmap[lbl]
77+
io.imsave('colored_40/%05d.png' % idx, colored_lbl)
78+
79+
print("Extracting labels (13 classes)...")
80+
for s in ['train', 'test']:
81+
os.makedirs(os.path.join(SEG13_DIR, s), exist_ok=True)
82+
idxs = splits[s+'Ndxs'].reshape(-1)
83+
84+
for idx in tqdm(idxs):
85+
lbl = labels_13[idx-1]
86+
path = os.path.join(SEG13_DIR, s, '%05d.png' % (idx))
87+
io.imsave(path, lbl, check_contrast=False)
88+
if save_colored:
89+
colored_lbl = cmap[lbl]
90+
io.imsave('colored_13/%05d.png' % idx, colored_lbl)
91+
92+
93+
def extract_depths(depths, splits, DEPTH_DIR, save_colored=False):
94+
depths = depths.transpose(0, 2, 1)
95+
if save_colored:
96+
os.makedirs('colored_depth', exist_ok=True)
97+
print("Extracting depths...")
98+
depths = (depths*1e3).astype(np.uint16)
99+
100+
for s in ['train', 'test']:
101+
os.makedirs(os.path.join(DEPTH_DIR, s), exist_ok=True)
102+
idxs = splits[s+'Ndxs'].reshape(-1)
103+
for idx in tqdm(idxs):
104+
depth = depths[idx-1]
105+
path = os.path.join(DEPTH_DIR, s, '%05d.png' % (idx))
106+
io.imsave(path, depth, check_contrast=False)
107+
108+
if save_colored:
109+
norm = plt.Normalize()
110+
colored = plt.cm.jet(norm(depth))
111+
plt.imsave('colored_depth/%05d.png' % (idx), colored)
112+
113+
if __name__ == '__main__':
114+
parser = argparse.ArgumentParser(description='RYU DATA Extraction')
115+
parser.add_argument('--mat', type=str, required=True,
116+
help='downloaded NYUv2 mat files. http://horatio.cs.nyu.edu/mit/silberman/nyu_depth_v2/nyu_depth_v2_labeled.mat')
117+
parser.add_argument('--data_root', type=str,
118+
required=True, help='the output dir')
119+
parser.add_argument('--save_colored', action='store_true', default=False,
120+
help="save colored labels and depth maps for visualization")
121+
parser.add_argument('--normal_zip', type=str, default=None,
122+
help='path to nyu_normals_gt.zip. https: // inf.ethz.ch/personal/ladickyl/nyu_normals_gt.zip')
123+
124+
args = parser.parse_args()
125+
126+
MAT_FILE = os.path.expanduser(args.mat)
127+
DATA_ROOT = os.path.expanduser(args.data_root)
128+
assert os.path.exists(MAT_FILE), "file does not exists: %s" % MAT_FILE
129+
130+
os.makedirs(DATA_ROOT, exist_ok=True)
131+
IMAGE_DIR = os.path.join(DATA_ROOT, 'image')
132+
SEG40_DIR = os.path.join(DATA_ROOT, 'seg40')
133+
SEG13_DIR = os.path.join(DATA_ROOT, 'seg13')
134+
DEPTH_DIR = os.path.join(DATA_ROOT, 'depth')
135+
splits = loadmat('splits.mat')
136+
137+
os.makedirs(IMAGE_DIR, exist_ok=True)
138+
os.makedirs(SEG40_DIR, exist_ok=True)
139+
os.makedirs(SEG13_DIR, exist_ok=True)
140+
os.makedirs(DEPTH_DIR, exist_ok=True)
141+
import time
142+
with h5py.File(MAT_FILE, 'r') as fr:
143+
images = fr["images"]
144+
labels = fr["labels"]
145+
depths = fr["depths"]
146+
147+
#extract_images(np.array(images), splits, IMAGE_DIR)
148+
#extract_labels(np.array(labels), splits, SEG40_DIR, SEG13_DIR, save_colored=args.save_colored )
149+
extract_depths(np.array(depths), splits, DEPTH_DIR, save_colored=args.save_colored)
150+
151+
if args.normal_zip is not None and os.path.exists(args.normal_zip):
152+
NORMAL_DIR = os.path.join(DATA_ROOT, 'normal')
153+
os.makedirs(NORMAL_DIR, exist_ok=True)
154+
with zipfile.ZipFile(args.normal_zip, 'r') as normal_zip:
155+
normal_zip.extractall(path=NORMAL_DIR)
156+
157+
if not os.path.exists(os.path.join( DATA_ROOT, 'splits.mat' )):
158+
shutil.copy2( 'splits.mat', os.path.join( DATA_ROOT, 'splits.mat' ))
159+

nyuv2.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#coding:utf-8
2+
import os
3+
import torch
4+
import torch.utils.data as data
5+
from PIL import Image
6+
from scipy.io import loadmat
7+
import numpy as np
8+
import glob
9+
from torchvision import transforms
10+
from torchvision.datasets import VisionDataset
11+
import random
12+
13+
def colormap(N=256, normalized=False):
14+
def bitget(byteval, idx):
15+
return ((byteval & (1 << idx)) != 0)
16+
17+
dtype = 'float32' if normalized else 'uint8'
18+
cmap = np.zeros((N, 3), dtype=dtype)
19+
for i in range(N):
20+
r = g = b = 0
21+
c = i
22+
for j in range(8):
23+
r = r | (bitget(c, 0) << 7-j)
24+
g = g | (bitget(c, 1) << 7-j)
25+
b = b | (bitget(c, 2) << 7-j)
26+
c = c >> 3
27+
28+
cmap[i] = np.array([r, g, b])
29+
30+
cmap = cmap/255 if normalized else cmap
31+
return cmap
32+
33+
class NYUv2(VisionDataset):
34+
"""NYUv2 dataset
35+
36+
Args:
37+
root (string): Root directory path.
38+
split (string, optional): 'train' for training set, and 'test' for test set. Default: 'train'.
39+
target_type (string, optional): Type of target to use, ``semantic``, ``depth`` or ``normal``.
40+
num_classes (int, optional): The number of classes, must be 40 or 13. Default:13.
41+
transform (callable, optional): A function/transform that takes in an PIL image and returns a transformed version.
42+
target_transform (callable, optional): A function/transform that takes in the target and transforms it.
43+
transforms (callable, optional): A function/transform that takes input sample and its target as entry and returns a transformed version.
44+
"""
45+
cmap = colormap()
46+
def __init__(self,
47+
root,
48+
split='train',
49+
target_type='semantic',
50+
num_classes=13,
51+
transforms=None,
52+
transform=None,
53+
target_transform=None):
54+
super( NYUv2, self ).__init__(root, transforms=transforms, transform=transform, target_transform=target_transform)
55+
assert(split in ('train', 'test'))
56+
self.root = root
57+
self.split = split
58+
self.target_type = target_type
59+
self.num_classes = num_classes
60+
self.train_idx = np.array([255, ] + list(range(num_classes)))
61+
62+
split_mat = loadmat(os.path.join(self.root, 'splits.mat'))
63+
idxs = split_mat[self.split+'Ndxs'].reshape(-1) - 1
64+
65+
img_names = os.listdir( os.path.join(self.root, 'image', self.split) )
66+
img_names.sort()
67+
images_dir = os.path.join(self.root, 'image', self.split)
68+
self.images = [os.path.join(images_dir, name) for name in img_names]
69+
70+
if self.target_type=='semantic':
71+
semantic_dir = os.path.join(self.root, 'seg%d'%self.num_classes, self.split)
72+
self.labels = [os.path.join(semantic_dir, name) for name in img_names]
73+
self.targets = self.labels
74+
75+
if self.target_type=='depth':
76+
depth_dir = os.path.join(self.root, 'depth', self.split)
77+
self.depths = [os.path.join(depth_dir, name) for name in img_names]
78+
self.targets = self.depths
79+
80+
if self.target_type=='normal':
81+
normal_dir = os.path.join(self.root, 'normal', self.split)
82+
self.normals = [os.path.join(normal_dir, name) for name in img_names]
83+
self.targets = self.normals
84+
85+
def __getitem__(self, idx):
86+
image = Image.open(self.images[idx])
87+
target = Image.open(self.targets[idx])
88+
if self.transforms is not None:
89+
image, target = self.transforms( image, target )
90+
return image, target
91+
92+
def __len__(self):
93+
return len(self.images)
94+
95+
if __name__=='__main__':
96+
from torchvision import transforms
97+
import matplotlib.pyplot as plt
98+
nyu_semantic13 = NYUv2( root='NYUv2', split='train', target_type='semantic', num_classes=13,
99+
transform=transforms.Compose([
100+
transforms.Resize(512),
101+
transforms.ToTensor()
102+
]),
103+
target_transform=transforms.Compose([
104+
transforms.Resize(512, interpolation=Image.NEAREST),
105+
transforms.Lambda(lambda lbl: torch.from_numpy( np.array(lbl, dtype='uint8')-1 ) ) # 0->255, 1->0, 2->1
106+
]),
107+
)
108+
109+
nyu_semantic40 = NYUv2( root='NYUv2', split='train', target_type='semantic', num_classes=40,
110+
transform=transforms.Compose([
111+
transforms.Resize(512),
112+
transforms.ToTensor()
113+
]),
114+
target_transform=transforms.Compose([
115+
transforms.Resize(512, interpolation=Image.NEAREST),
116+
transforms.Lambda(lambda lbl: torch.from_numpy( np.array(lbl, dtype='uint8')-1 ) ) # 0->255, 1->0, 2->1
117+
]),
118+
)
119+
120+
nyu_depth = NYUv2( root='NYUv2', split='train', target_type='depth',
121+
transform=transforms.Compose([
122+
transforms.Resize(512),
123+
transforms.ToTensor()
124+
]),
125+
target_transform=transforms.Compose([
126+
transforms.Resize(512),
127+
transforms.Lambda(lambda lbl: torch.from_numpy( np.array(lbl, dtype='float') )/1e3 ) # uint16 to depth
128+
]),
129+
)
130+
131+
nyu_normal = NYUv2( root='NYUv2', split='train', target_type='normal',
132+
transform=transforms.Compose([
133+
transforms.Resize(512),
134+
transforms.ToTensor()
135+
]),
136+
target_transform=transforms.Compose([
137+
transforms.ToTensor(),
138+
transforms.Lambda(lambda normal: normal * 2 - 1)
139+
]),
140+
)
141+
142+
os.makedirs('test', exist_ok=True)
143+
# Semantic
144+
img_id = 0
145+
146+
img, lbl13 = nyu_semantic13[img_id]
147+
Image.fromarray((img*255).numpy().transpose( 1,2,0 ).astype('uint8')).save('test/image.png')
148+
Image.fromarray( nyu_semantic13.cmap[ (lbl13.numpy().astype('uint8')+1) ] ).save('test/semantic13.png')
149+
150+
img, lbl40 = nyu_semantic40[img_id]
151+
Image.fromarray( nyu_semantic40.cmap[ (lbl40.numpy().astype('uint8')+1) ] ).save('test/semantic40.png')
152+
153+
# Depth
154+
img, depth = nyu_depth[img_id]
155+
norm = plt.Normalize()
156+
depth = plt.cm.jet(norm(depth))
157+
plt.imsave('test/depth.png', depth)
158+
159+
# Normal
160+
img, normal = nyu_normal[img_id]
161+
normal = (normal+1)/2
162+
Image.fromarray((normal*255).numpy().transpose( 1,2,0 ).astype('uint8')).save('test/normal.png')
163+
164+

test/depth.png

82.6 KB
Loading

test/image.png

276 KB
Loading

test/normal.png

184 KB
Loading

test/semantic13.png

7.18 KB
Loading

test/semantic40.png

7.57 KB
Loading

test_labels_13/nyuv2_test_class13.tgz

-3.77 MB
Binary file not shown.
-1.26 MB
Binary file not shown.
-4.62 MB
Binary file not shown.

0 commit comments

Comments
 (0)