├── src
├── options
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-36.pyc
│ │ ├── base_options.cpython-36.pyc
│ │ └── train_options.cpython-36.pyc
│ ├── test_options.py
│ ├── train_options.py
│ └── base_options.py
├── util
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── html.cpython-36.pyc
│ │ ├── util.cpython-36.pyc
│ │ ├── __init__.cpython-36.pyc
│ │ └── visualizer.cpython-36.pyc
│ ├── png.py
│ ├── image_pool.py
│ ├── html.py
│ ├── util.py
│ ├── get_data.py
│ └── visualizer.py
├── BilinearSampling.py
├── MatInverse.py
├── KITTIdataset.py
├── testKITTI.py
├── train_main_ddvo.py
├── train_main_posenet.py
├── train_main_finetune.py
├── ImagePyramid.py
├── LKVOLearnerFinetune.py
├── SfMLearner.py
├── LKVOLearner.py
├── networks.py
└── DirectVOLayer.py
├── run_test.sh
├── run_train_posenet.sh
├── run_train_finetune.sh
├── LICENSE
├── README.md
└── test_files_eigen.txt
/src/options/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/util/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/util/__pycache__/html.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MightyChaos/LKVOLearner/HEAD/src/util/__pycache__/html.cpython-36.pyc
--------------------------------------------------------------------------------
/src/util/__pycache__/util.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MightyChaos/LKVOLearner/HEAD/src/util/__pycache__/util.cpython-36.pyc
--------------------------------------------------------------------------------
/src/util/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MightyChaos/LKVOLearner/HEAD/src/util/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/src/options/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MightyChaos/LKVOLearner/HEAD/src/options/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/src/util/__pycache__/visualizer.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MightyChaos/LKVOLearner/HEAD/src/util/__pycache__/visualizer.cpython-36.pyc
--------------------------------------------------------------------------------
/src/options/__pycache__/base_options.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MightyChaos/LKVOLearner/HEAD/src/options/__pycache__/base_options.cpython-36.pyc
--------------------------------------------------------------------------------
/src/options/__pycache__/train_options.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MightyChaos/LKVOLearner/HEAD/src/options/__pycache__/train_options.cpython-36.pyc
--------------------------------------------------------------------------------
/run_test.sh:
--------------------------------------------------------------------------------
1 | DATAROOT=../kitti/
2 | PWD=$(pwd)
3 | CKPT=$PWD/checkpoints/finetune/5_model.pth
4 | # CKPT=$PWD/posenet+ddvo.pth
5 | OUTPUT=$PWD/posenet+ddvo
6 | CUDA_VISIBLE_DEVICES=0 nice -10 python src/testKITTI.py --dataset_root $DATAROOT --ckpt_file $CKPT --output_path $OUTPUT --test_file_list test_files_eigen.txt
7 |
8 | python2 ~/SfMLearner/kitti_eval/eval_depth.py --kitti_dir=$DATAROOT --pred_file=$OUTPUT.npy --test_file_list test_files_eigen.txt
--------------------------------------------------------------------------------
/run_train_posenet.sh:
--------------------------------------------------------------------------------
1 | PWD=$(pwd)
2 | mkdir $PWD/checkpoints/
3 | EXPNAME=posenet
4 | CHECKPOINT_DIR=$PWD/checkpoints/$EXPNAME
5 | mkdir $CHECKPOINT_DIR
6 | DATAROOT_DIR=$PWD/data_kitti
7 | CUDA_VISIBLE_DEVICES=0 python src/train_main_posenet.py --dataroot $DATAROOT_DIR\
8 | --checkpoints_dir $CHECKPOINT_DIR --which_epoch -1 --save_latest_freq 1000\
9 | --batchSize 1 --display_freq 50 --name $EXPNAME --lambda_S 0.01 --smooth_term 2nd --use_ssim --display_port 8009
10 |
--------------------------------------------------------------------------------
/run_train_finetune.sh:
--------------------------------------------------------------------------------
1 | MODEL_ID=9
2 | PWD=$(pwd)
3 | mkdir $PWD/checkpoints/
4 | EXPNAME=finetune
5 | CHECKPOINT_DIR=$PWD/checkpoints/$EXPNAME
6 | mkdir $CHECKPOINT_DIR
7 | # copy learnt model from PoseNet
8 | POSENET_CKPT_DIR=$PWD/checkpoints/posenet
9 |
10 | cp $(printf "%s/%s_pose_net.pth" "$POSENET_CKPT_DIR" "$MODEL_ID") $CHECKPOINT_DIR/pose_net.pth
11 | cp $(printf "%s/%s_depth_net.pth" "$POSENET_CKPT_DIR" "$MODEL_ID") $CHECKPOINT_DIR/depth_net.pth
12 |
13 | DATAROOT_DIR=$PWD/data_kitti
14 |
15 | CUDA_VISIBLE_DEVICES=0 python src/train_main_finetune.py --dataroot $DATAROOT_DIR\
16 | --checkpoints_dir $CHECKPOINT_DIR --which_epoch -1 --save_latest_freq 1000\
17 | --batchSize 1 --display_freq 50 --name $EXPNAME\
18 | --lk_level 1 --lambda_S 0.01 --smooth_term 2nd --use_ssim --display_port 8009 --epoch_num 10
19 | --lr 0.00001
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/BilinearSampling.py:
--------------------------------------------------------------------------------
1 | import torch
2 | from torch import FloatTensor
3 | from torch.autograd import Variable
4 | from timeit import default_timer as timer
5 | from torch.nn.functional import grid_sample
6 | from torch.nn import ReplicationPad2d
7 |
8 |
9 | def grid_bilinear_sampling(A, x, y):
10 | batch_size, k, h, w = A.size()
11 | x_norm = x/((w-1)/2) - 1
12 | y_norm = y/((h-1)/2) - 1
13 | grid = torch.cat((x_norm.view(batch_size, h, w, 1), y_norm.view(batch_size, h, w, 1)), 3)
14 | Q = grid_sample(A, grid, mode='bilinear')
15 | in_view_mask = Variable(((x_norm.data > -1+2/w) & (x_norm.data < 1-2/w) & (y_norm.data > -1+2/h) & (y_norm.data < 1-2/h)).type_as(A.data))
16 | # in_view_mask = Variable(((x.data > 1) & (x.data < w-2) & (y.data > 1) & (y.data < h-2)).type_as(A.data))
17 | # in_view_mask = Variable(((x.data > -1+3/w) & (x.data < 1-3/w) & (y.data > -1+3/h) & (y.data < 1-3/h)).type_as(A.data))
18 | return Q.view(batch_size, k, h*w), in_view_mask
19 |
--------------------------------------------------------------------------------
/src/options/test_options.py:
--------------------------------------------------------------------------------
1 | from .base_options import BaseOptions
2 |
3 |
4 | class TestOptions(BaseOptions):
5 | def initialize(self):
6 | BaseOptions.initialize(self)
7 | self.parser.add_argument('--ntest', type=int, default=float("inf"), help='# of test examples.')
8 | self.parser.add_argument('--results_dir', type=str, default='./results/', help='saves results here.')
9 | self.parser.add_argument('--aspect_ratio', type=float, default=1.0, help='aspect ratio of result images')
10 | self.parser.add_argument('--phase', type=str, default='test', help='train, val, test, etc')
11 | self.parser.add_argument('--which_epoch', type=str, default='latest', help='which epoch to load? set to latest to use latest cached model')
12 | self.parser.add_argument('--how_many', type=int, default=50, help='how many test images to run')
13 | self.isTrain = False
14 |
15 | self.parser.add_argument('--no_lsgan', action='store_true', help='do *not* use least square GAN, if false, use vanilla GAN')
16 |
--------------------------------------------------------------------------------
/src/util/png.py:
--------------------------------------------------------------------------------
1 | import struct
2 | import zlib
3 |
4 | def encode(buf, width, height):
5 | """ buf: must be bytes or a bytearray in py3, a regular string in py2. formatted RGBRGB... """
6 | assert (width * height * 3 == len(buf))
7 | bpp = 3
8 |
9 | def raw_data():
10 | # reverse the vertical line order and add null bytes at the start
11 | row_bytes = width * bpp
12 | for row_start in range((height - 1) * width * bpp, -1, -row_bytes):
13 | yield b'\x00'
14 | yield buf[row_start:row_start + row_bytes]
15 |
16 | def chunk(tag, data):
17 | return [
18 | struct.pack("!I", len(data)),
19 | tag,
20 | data,
21 | struct.pack("!I", 0xFFFFFFFF & zlib.crc32(data, zlib.crc32(tag)))
22 | ]
23 |
24 | SIGNATURE = b'\x89PNG\r\n\x1a\n'
25 | COLOR_TYPE_RGB = 2
26 | COLOR_TYPE_RGBA = 6
27 | bit_depth = 8
28 | return b''.join(
29 | [ SIGNATURE ] +
30 | chunk(b'IHDR', struct.pack("!2I5B", width, height, bit_depth, COLOR_TYPE_RGB, 0, 0, 0)) +
31 | chunk(b'IDAT', zlib.compress(b''.join(raw_data()), 9)) +
32 | chunk(b'IEND', b'')
33 | )
34 |
--------------------------------------------------------------------------------
/src/util/image_pool.py:
--------------------------------------------------------------------------------
1 | import random
2 | import numpy as np
3 | import torch
4 | from torch.autograd import Variable
5 | class ImagePool():
6 | def __init__(self, pool_size):
7 | self.pool_size = pool_size
8 | if self.pool_size > 0:
9 | self.num_imgs = 0
10 | self.images = []
11 |
12 | def query(self, images):
13 | if self.pool_size == 0:
14 | return images
15 | return_images = []
16 | for image in images.data:
17 | image = torch.unsqueeze(image, 0)
18 | if self.num_imgs < self.pool_size:
19 | self.num_imgs = self.num_imgs + 1
20 | self.images.append(image)
21 | return_images.append(image)
22 | else:
23 | p = random.uniform(0, 1)
24 | if p > 0.5:
25 | random_id = random.randint(0, self.pool_size-1)
26 | tmp = self.images[random_id].clone()
27 | self.images[random_id] = image
28 | return_images.append(tmp)
29 | else:
30 | return_images.append(image)
31 | return_images = Variable(torch.cat(return_images, 0))
32 | return return_images
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2018, MightyChaos
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/src/options/train_options.py:
--------------------------------------------------------------------------------
1 | from .base_options import BaseOptions
2 |
3 |
4 | class TrainOptions(BaseOptions):
5 | def initialize(self):
6 | BaseOptions.initialize(self)
7 | self.parser.add_argument('--lk_level', type=int, default=1, help='number of image levels for direct vo')
8 | self.parser.add_argument('--use_ssim', default=False, action='store_true', help='use ssim loss')
9 | self.parser.add_argument('--smooth_term', type=str, default='lap', help='smoothness term type, choose between lap, 1st, 2nd')
10 | self.parser.add_argument('--lambda_S', type=float, default=.01, help='smoothness cost weight')
11 | self.parser.add_argument('--lambda_E', type=float, default=.01, help='explainable mask regulariation cost weight')
12 | self.parser.add_argument('--epoch_num', type=int, default=20, help='number of epochs for training')
13 | self.parser.add_argument('--display_freq', type=int, default=100, help='frequency of showing training results on screen')
14 | self.parser.add_argument('--print_freq', type=int, default=10, help='frequency of showing training results on console')
15 | self.parser.add_argument('--save_latest_freq', type=int, default=5000, help='frequency of saving the latest results')
16 | self.parser.add_argument('--phase', type=str, default='train', help='train, val, test, etc')
17 | self.parser.add_argument('--which_epoch', type=int, default=-1, help='which epoch to load? set to epoch number, set -1 to train from scratch')
18 | self.parser.add_argument('--niter', type=int, default=100, help='# of iter at starting learning rate')
19 | self.parser.add_argument('--niter_decay', type=int, default=100, help='# of iter to linearly decay learning rate to zero')
20 | self.parser.add_argument('--beta1', type=float, default=0.5, help='momentum term of adam')
21 | self.parser.add_argument('--lr', type=float, default=0.0002, help='initial learning rate for adam')
22 | self.parser.add_argument('--no_html', action='store_true', help='do not save intermediate training results to [opt.checkpoints_dir]/[opt.name]/web/')
23 | self.isTrain = True
24 |
--------------------------------------------------------------------------------
/src/util/html.py:
--------------------------------------------------------------------------------
1 | import dominate
2 | from dominate.tags import *
3 | import os
4 |
5 |
6 | class HTML:
7 | def __init__(self, web_dir, title, reflesh=0):
8 | self.title = title
9 | self.web_dir = web_dir
10 | self.img_dir = os.path.join(self.web_dir, 'images')
11 | if not os.path.exists(self.web_dir):
12 | os.makedirs(self.web_dir)
13 | if not os.path.exists(self.img_dir):
14 | os.makedirs(self.img_dir)
15 | # print(self.img_dir)
16 |
17 | self.doc = dominate.document(title=title)
18 | if reflesh > 0:
19 | with self.doc.head:
20 | meta(http_equiv="reflesh", content=str(reflesh))
21 |
22 | def get_image_dir(self):
23 | return self.img_dir
24 |
25 | def add_header(self, str):
26 | with self.doc:
27 | h3(str)
28 |
29 | def add_table(self, border=1):
30 | self.t = table(border=border, style="table-layout: fixed;")
31 | self.doc.add(self.t)
32 |
33 | def add_images(self, ims, txts, links, width=400):
34 | self.add_table()
35 | with self.t:
36 | with tr():
37 | for im, txt, link in zip(ims, txts, links):
38 | with td(style="word-wrap: break-word;", halign="center", valign="top"):
39 | with p():
40 | with a(href=os.path.join('images', link)):
41 | img(style="width:%dpx" % width, src=os.path.join('images', im))
42 | br()
43 | p(txt)
44 |
45 | def save(self):
46 | html_file = '%s/index.html' % self.web_dir
47 | f = open(html_file, 'wt')
48 | f.write(self.doc.render())
49 | f.close()
50 |
51 |
52 | if __name__ == '__main__':
53 | html = HTML('web/', 'test_html')
54 | html.add_header('hello world')
55 |
56 | ims = []
57 | txts = []
58 | links = []
59 | for n in range(4):
60 | ims.append('image_%d.png' % n)
61 | txts.append('text_%d' % n)
62 | links.append('image_%d.png' % n)
63 | html.add_images(ims, txts, links)
64 | html.save()
65 |
--------------------------------------------------------------------------------
/src/util/util.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import torch
3 | import numpy as np
4 | from PIL import Image
5 | import inspect, re
6 | import numpy as np
7 | import os
8 | import collections
9 |
10 | # Converts a Tensor into a Numpy array
11 | # |imtype|: the desired type of the converted numpy array
12 | def tensor2im(image_tensor, imtype=np.uint8):
13 | image_numpy = image_tensor[0].cpu().float().numpy()
14 | image_numpy = (np.transpose(image_numpy, (1, 2, 0)) + 1) / 2.0 * 255.0
15 | return image_numpy.astype(imtype)
16 |
17 |
18 | def diagnose_network(net, name='network'):
19 | mean = 0.0
20 | count = 0
21 | for param in net.parameters():
22 | if param.grad is not None:
23 | mean += torch.mean(torch.abs(param.grad.data))
24 | count += 1
25 | if count > 0:
26 | mean = mean / count
27 | print(name)
28 | print(mean)
29 |
30 |
31 | def save_image(image_numpy, image_path):
32 | image_pil = Image.fromarray(image_numpy)
33 | image_pil.save(image_path)
34 |
35 | def info(object, spacing=10, collapse=1):
36 | """Print methods and doc strings.
37 | Takes module, class, list, dictionary, or string."""
38 | methodList = [e for e in dir(object) if isinstance(getattr(object, e), collections.Callable)]
39 | processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
40 | print( "\n".join(["%s %s" %
41 | (method.ljust(spacing),
42 | processFunc(str(getattr(object, method).__doc__)))
43 | for method in methodList]) )
44 |
45 | def varname(p):
46 | for line in inspect.getframeinfo(inspect.currentframe().f_back)[3]:
47 | m = re.search(r'\bvarname\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)', line)
48 | if m:
49 | return m.group(1)
50 |
51 | def print_numpy(x, val=True, shp=False):
52 | x = x.astype(np.float64)
53 | if shp:
54 | print('shape,', x.shape)
55 | if val:
56 | x = x.flatten()
57 | print('mean = %3.3f, min = %3.3f, max = %3.3f, median = %3.3f, std=%3.3f' % (
58 | np.mean(x), np.min(x), np.max(x), np.median(x), np.std(x)))
59 |
60 |
61 | def mkdirs(paths):
62 | if isinstance(paths, list) and not isinstance(paths, str):
63 | for path in paths:
64 | mkdir(path)
65 | else:
66 | mkdir(paths)
67 |
68 |
69 | def mkdir(path):
70 | if not os.path.exists(path):
71 | os.makedirs(path)
72 |
--------------------------------------------------------------------------------
/src/MatInverse.py:
--------------------------------------------------------------------------------
1 | import torch
2 | from torch import FloatTensor
3 | from torch.autograd import Variable
4 | from timeit import default_timer as timer
5 | from torch.autograd import gradcheck
6 |
7 | class Inverse(torch.autograd.Function):
8 |
9 | def forward(self, input):
10 | h, w = input.size()
11 | assert(h == w)
12 | H = input.inverse()
13 | self.save_for_backward(H)
14 | return H
15 |
16 | def backward(self, grad_output):
17 | # print(grad_output.is_contiguous())
18 | H, = self.saved_tensors
19 | h, w = H.size()
20 | assert(h == w)
21 | Hl = H.t().repeat(1, h).view(h*h, h, 1)
22 | # print(Hl.view(batch_size, h, h, h, 1))
23 | Hr = H.repeat(h, 1).view(h*h, 1, h)
24 | # print(Hr.view(batch_size, h, h, 1, h))
25 |
26 | r = Hl.bmm(Hr).view(h, h, h, h) * \
27 | grad_output.contiguous().view(1, 1, h, h).expand(h, h, h, h)
28 | # print(r.size())
29 | return -r.sum(-1).sum(-1)
30 | # print(r)
31 |
32 | def inv(input):
33 | return Inverse()(input)
34 |
35 | class InverseBatch(torch.autograd.Function):
36 |
37 | def forward(self, input):
38 | batch_size, h, w = input.size()
39 | assert(h == w)
40 | H = torch.Tensor(batch_size, h, h).type_as(input)
41 | for i in range(0, batch_size):
42 | H[i, :, :] = input[i, :, :].inverse()
43 | self.save_for_backward(H)
44 | return H
45 |
46 | def backward(self, grad_output):
47 | # print(grad_output.is_contiguous())
48 | H, = self.saved_tensors
49 | [batch_size, h, w] = H.size()
50 | assert(h == w)
51 | Hl = H.transpose(1,2).repeat(1, 1, h).view(batch_size*h*h, h, 1)
52 | # print(Hl.view(batch_size, h, h, h, 1))
53 | Hr = H.repeat(1, h, 1).view(batch_size*h*h, 1, h)
54 | # print(Hr.view(batch_size, h, h, 1, h))
55 |
56 | r = Hl.bmm(Hr).view(batch_size, h, h, h, h) * \
57 | grad_output.contiguous().view(batch_size, 1, 1, h, h).expand(batch_size, h, h, h, h)
58 | # print(r.size())
59 | return -r.sum(-1).sum(-1)
60 | # print(r)
61 |
62 | def inv_batch(input):
63 | return InverseBatch()(input)
64 |
65 |
66 | if __name__ == "__main__":
67 |
68 | W = torch.rand(2,2)
69 | s = timer()
70 | invH = inv(Variable(W, requires_grad=True))
71 | print(timer() - s)
72 | c = invH.mean()
73 | print(c)
74 | c.backward()
75 | print(timer()-s)
76 | test = gradcheck(inv, (Variable(W, requires_grad=True),), eps=1e-5, atol=1e-4)
77 | print(test)
78 |
--------------------------------------------------------------------------------
/src/KITTIdataset.py:
--------------------------------------------------------------------------------
1 | from torch.utils.data import Dataset, DataLoader
2 | import numpy as np
3 | import scipy.io as sio
4 | from PIL import Image
5 | import os
6 |
7 |
8 | class KITTIdataset(Dataset):
9 | """KITTIdataset"""
10 | def __init__(self, list_file='train.txt', data_root_path='/home/chaoyang/LKVOLearner/data_kitti', img_size=[128, 416], bundle_size=3):
11 | self.data_root_path = data_root_path
12 | self.img_size = img_size
13 | self.bundle_size = bundle_size
14 | self.frame_pathes = []
15 | list_file = os.path.join(data_root_path, list_file)
16 | with open(list_file) as file:
17 | for line in file:
18 | frame_path = line.strip()
19 | seq_path, frame_name = frame_path.split(" ")
20 | # print(seq_path)
21 | if seq_path in ['2011_09_26_drive_0119_sync_02', '2011_09_28_drive_0225_sync_02',
22 | '2011_09_29_drive_0108_sync_02', '2011_09_30_drive_0072_sync_02',
23 | '2011_10_03_drive_0058_sync_02', '2011_09_29_drive_0108_sync_03']:
24 | print(seq_path)
25 | continue
26 | frame_path = os.path.join(seq_path, frame_name)
27 | self.frame_pathes.append(frame_path)
28 | # print(frame_path)
29 | # self.frame_pathes = self.frame_pathes[0:40000:800]
30 |
31 | def __len__(self):
32 | return len(self.frame_pathes)
33 |
34 | def __getitem__(self, item):
35 | # read camera intrinsics
36 | cam_file = os.path.join(self.data_root_path, self.frame_pathes[item]+'_cam.txt')
37 | with open(cam_file) as file:
38 | cam_intrinsics = [float(x) for x in next(file).split(',')]
39 | # camparams = dict(fx=cam_intrinsics[0], cx=cam_intrinsics[2],
40 | # fy=cam_intrinsics[4], cy=cam_intrinsics[5])
41 | camparams = np.asarray(cam_intrinsics)
42 |
43 | # read image bundle
44 | img_file = os.path.join(self.data_root_path, self.frame_pathes[item]+'.jpg')
45 | frames_cat = np.array(Image.open(img_file))
46 | # slice the image into #bundle_size number of images
47 | frame_list = []
48 | for i in range(self.bundle_size):
49 | frame_list.append(frames_cat[:,i*self.img_size[1]:(i+1)*self.img_size[1],:])
50 | frames = np.asarray(frame_list).astype(float).transpose(0, 3, 1, 2)
51 |
52 | return frames, camparams
53 |
54 | if __name__ == "__main__":
55 | dataset = KITTIdataset()
56 | dataset.__getitem__(0)
57 | for i, data in enumerate(dataset):
58 | print(data[1])
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Learning Depth from Monocular Videos using Direct Methods
2 |
3 |
4 | Implementation of the methods in "[Learning Depth from Monocular Videos using Direct Methods](http://openaccess.thecvf.com/content_cvpr_2018/papers/Wang_Learning_Depth_From_CVPR_2018_paper.pdf)".
5 | If you find this code useful, please cite our paper:
6 |
7 | ```
8 | @InProceedings{Wang_2018_CVPR,
9 | author = {Wang, Chaoyang and Miguel Buenaposada, José and Zhu, Rui and Lucey, Simon},
10 | title = {Learning Depth From Monocular Videos Using Direct Methods},
11 | booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR)},
12 | month = {June},
13 | year = {2018}
14 | }
15 | ```
16 | ## Dependencies
17 | - Python 3.6
18 | - PyTorch 0.3.1 (latter or eariler version of Pytorch is non-compatible.)
19 |
20 | - visdom, dominate
21 |
22 |
23 | ## Training
24 | ### data preparation
25 | We refer "[SfMLeaner](https://github.com/tinghuiz/SfMLearner)" to prepare the training data from KITTI. We assume the processed data is put in directory "./data_kitti/".
26 |
27 | ### training with different pose prediction modules
28 | Start visdom server before for inspecting learning progress before starting the training process.
29 | ```
30 | python -m visdom.server -port 8009
31 | ```
32 | 1. #### train from scratch with PoseNet
33 | ```
34 | bash run_train_posenet.sh
35 | ```
36 | see [run_train_posenet.sh](https://github.com/MightyChaos/LKVOLearner/blob/master/run_train_posenet.sh) for details.
37 |
38 | 2. #### finetune with DDVO
39 | Use pretrained posenet to give initialization for DDVO. Corresponds to the results reported as "PoseNet+DDVO" in the paper.
40 | ```
41 | bash run_train_finetune.sh
42 | ```
43 | see [run_train_finetune.sh](https://github.com/MightyChaos/LKVOLearner/blob/master/run_train_finetune.sh) for details.
44 |
45 | ## Testing
46 | - Pretrained depth network reported as "Posenet-DDVO(CS+K)" in the paper [[download](https://drive.google.com/file/d/1SJWLfA7kqpERj_U2gYXl7Vuy1eQyOO_K/view?usp=sharing)].
47 | - Depth prediction results on KITTI eigen test split(see Table 1 in the paper): [[Posenet(K)](https://drive.google.com/open?id=1Wj7ulSimrvrzNx4TRd-JspmX3DJwgPiV)], [[DDVO(K)](https://drive.google.com/open?id=1wiODwgX_Vm_w7fVK1y_X5CNJTtgaPwcN)], [[Posenet+DDVO(K)](https://drive.google.com/open?id=1uUQJLcUOoY2hG6QS_F-wbM3GDAjD-Z5h)],[[Posenet+DDVO(CS+K)](https://drive.google.com/open?id=1hp4zFgK5NSNGdvaQL2ZumeinMQY_-AwK)]
48 |
49 | - To test yourself:
50 | ```
51 | CUDA_VISIBLE_DEVICES=0 nice -10 python src/testKITTI.py --dataset_root $DATAROOT --ckpt_file $CKPT --output_path $OUTPUT --test_file_list test_files_eigen.txt
52 | ```
53 |
54 | ## Evaluation
55 | We again refer to "[SfMLeaner](https://github.com/tinghuiz/SfMLearner)" for their evaluation code.
56 |
57 |
58 | ## Acknowledgement
59 | Part of the code structure is borrowed from "[Pytorch CycleGAN](https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix)"
--------------------------------------------------------------------------------
/src/options/base_options.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import os
3 | from util import util
4 | import torch
5 |
6 | class BaseOptions():
7 | def __init__(self):
8 | self.parser = argparse.ArgumentParser()
9 | self.initialized = False
10 |
11 | def initialize(self):
12 | self.parser.add_argument('--dataroot', required=True, help='path to images (should have subfolders trainA, trainB, valA, valB, etc)')
13 | self.parser.add_argument('--batchSize', type=int, default=1, help='input batch size')
14 | self.parser.add_argument('--imH', type=int, default=128, help='imH')
15 | self.parser.add_argument('--imW', type=int, default=416, help='imW')
16 | self.parser.add_argument('--max_lk_iter_num', type=int, default=10, help='maximum iteration for LK update')
17 |
18 | self.parser.add_argument('--gpu_ids', type=str, default='0', help='gpu ids: e.g. 0 0,1,2, 0,2. use -1 for CPU')
19 | self.parser.add_argument('--name', type=str, default='experiment_name', help='name of the experiment. It decides where to store samples and models')
20 |
21 | self.parser.add_argument('--nThreads', default=2, type=int, help='# threads for loading data')
22 | self.parser.add_argument('--checkpoints_dir', type=str, default='./checkpoints', help='models are saved here')
23 |
24 | self.parser.add_argument('--display_winsize', type=int, default=256, help='display window size')
25 | self.parser.add_argument('--display_id', type=int, default=1, help='window id of the web display')
26 | self.parser.add_argument('--display_port', type=int, default=8097, help='visdom port of the web display')
27 | self.parser.add_argument('--display_single_pane_ncols', type=int, default=0, help='if positive, display all images in a single visdom web panel with certain number of images per row.')
28 |
29 |
30 |
31 | def parse(self):
32 | if not self.initialized:
33 | self.initialize()
34 | self.opt = self.parser.parse_args()
35 | self.opt.isTrain = self.isTrain # train or test
36 |
37 | str_ids = self.opt.gpu_ids.split(',')
38 | self.opt.gpu_ids = []
39 | for str_id in str_ids:
40 | id = int(str_id)
41 | if id >= 0:
42 | self.opt.gpu_ids.append(id)
43 |
44 | # set gpu ids
45 | if len(self.opt.gpu_ids) > 0:
46 | torch.cuda.set_device(self.opt.gpu_ids[0])
47 |
48 | args = vars(self.opt)
49 |
50 | print('------------ Options -------------')
51 | for k, v in sorted(args.items()):
52 | print('%s: %s' % (str(k), str(v)))
53 | print('-------------- End ----------------')
54 |
55 | # save to the disk
56 | expr_dir = os.path.join(self.opt.checkpoints_dir, self.opt.name)
57 | util.mkdirs(expr_dir)
58 | file_name = os.path.join(expr_dir, 'opt.txt')
59 | with open(file_name, 'wt') as opt_file:
60 | opt_file.write('------------ Options -------------\n')
61 | for k, v in sorted(args.items()):
62 | opt_file.write('%s: %s\n' % (str(k), str(v)))
63 | opt_file.write('-------------- End ----------------\n')
64 | return self.opt
65 |
--------------------------------------------------------------------------------
/src/testKITTI.py:
--------------------------------------------------------------------------------
1 | from networks import VggDepthEstimator
2 | from LKVOLearner import FlipLR
3 | import torch
4 | from torch.autograd import Variable
5 | import os
6 | from PIL import Image
7 | import numpy as np
8 | import matplotlib.pyplot as plt
9 | import argparse
10 |
11 | """
12 | CUDA_VISIBLE_DEVICES=1 nice -10 python3 testKITTI.py --dataset_root /newfoundland/chaoyang/kitti --ckpt_file /home/chaoyang/LKVOLearner/checkpoints/checkpoints_19_416_scratch/9_model.pth --test_file_list
13 | """
14 | parser = argparse.ArgumentParser()
15 |
16 | parser.add_argument("--dataset_root", type=str, default="/newfoundland/chaoyang/kitti", help="dataset root path")
17 | parser.add_argument("--test_file_list", type=str, default="/newfoundland/chaoyang/SfMLearner/data/kitti/test_files_eigen.txt", help="test file list")
18 | parser.add_argument("--ckpt_file", type=str, default=None, help="checkpoint file")
19 | parser.add_argument("--output_path", type=str, default="pred_depths", help="output path")
20 | parser.add_argument("--use_pp", default=False, action="store_true", help='use post processing')
21 |
22 | FLAGS = parser.parse_args()
23 |
24 | # dataset_root = "/newfoundland/chaoyang/kitti"
25 | # model_path = "/home/chaoyang/LKVOLearner/checkpoints_new/12_model.pth"
26 | # test_file_list = "/newfoundland/chaoyang/SfMLearner/data/kitti/test_files_eigen.txt"
27 | dataset_root = FLAGS.dataset_root
28 | model_path = FLAGS.ckpt_file
29 | test_file_list = FLAGS.test_file_list
30 | output_path = FLAGS.output_path
31 |
32 | img_size = [128, 416]
33 | vgg_depth_net = VggDepthEstimator(img_size)
34 | vgg_depth_net.load_state_dict(torch.load(model_path))
35 | vgg_depth_net.cuda()
36 |
37 | fliplr = FlipLR(imW=img_size[1], dim_w=2).cuda()
38 |
39 | def read_text_lines(file_path):
40 | f = open(file_path, 'r')
41 | lines = f.readlines()
42 | f.close()
43 | lines = [l.rstrip() for l in lines]
44 | return lines
45 |
46 | test_files = read_text_lines(test_file_list)
47 | pred_depths = []
48 | i = 0
49 | for filename in test_files:
50 | print(i)
51 | filename = filename.split()[0]
52 | im_path = os.path.join(dataset_root, filename)
53 | img_pil = Image.open(im_path).resize((img_size[1], img_size[0]), Image.ANTIALIAS)
54 | # img_pil.save('kitti_test_images/%04d.png'%(i))
55 | img = np.array(img_pil)
56 | # print(img.shape)
57 | img = img.transpose(2, 0, 1)
58 | # print(img.shape)
59 | print(filename)
60 | img_var = Variable(torch.from_numpy(img).float().cuda(), volatile=True)
61 |
62 |
63 | if FLAGS.use_pp:
64 | # flip image
65 | img_vars = (torch.cat((fliplr(img_var).unsqueeze(0), img_var.unsqueeze(0)), 0)-127)/127
66 | pred_depth_pyramid = vgg_depth_net.forward(img_vars)
67 | depth = pred_depth_pyramid[0]
68 | print(depth.size())
69 | depth_mean = (fliplr(depth[0:1, :, :]) + depth[1:2, :, :])*.5
70 | pred_depths.append(depth_mean.data.cpu().squeeze().numpy())
71 | # compute mean
72 | else:
73 | pred_depth_pyramid = vgg_depth_net.forward((img_var.unsqueeze(0)-127)/127)
74 | pred_depths.append(pred_depth_pyramid[0].data.cpu().squeeze().numpy())
75 | i = i+1
76 | # if i==3:
77 | # break
78 | pred_depths = np.asarray(pred_depths)
79 | print(pred_depths.shape)
80 | np.save(output_path, 1/pred_depths)
81 | import scipy.io as sio
82 | sio.savemat(output_path, {'D': pred_depths})
83 | # print(pred_depth_pyramid[0].size())
84 | # plt.imshow(pred_depth_pyramid[0].data.cpu().squeeze().numpy())
85 | # plt.show()
86 |
--------------------------------------------------------------------------------
/src/util/get_data.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import os
3 | import tarfile
4 | import requests
5 | from warnings import warn
6 | from zipfile import ZipFile
7 | from bs4 import BeautifulSoup
8 | from os.path import abspath, isdir, join, basename
9 |
10 |
11 | class GetData(object):
12 | """
13 |
14 | Download CycleGAN or Pix2Pix Data.
15 |
16 | Args:
17 | technique : str
18 | One of: 'cyclegan' or 'pix2pix'.
19 | verbose : bool
20 | If True, print additional information.
21 |
22 | Examples:
23 | >>> from util.get_data import GetData
24 | >>> gd = GetData(technique='cyclegan')
25 | >>> new_data_path = gd.get(save_path='./datasets') # options will be displayed.
26 |
27 | """
28 |
29 | def __init__(self, technique='cyclegan', verbose=True):
30 | url_dict = {
31 | 'pix2pix': 'https://people.eecs.berkeley.edu/~tinghuiz/projects/pix2pix/datasets',
32 | 'cyclegan': 'https://people.eecs.berkeley.edu/~taesung_park/CycleGAN/datasets'
33 | }
34 | self.url = url_dict.get(technique.lower())
35 | self._verbose = verbose
36 |
37 | def _print(self, text):
38 | if self._verbose:
39 | print(text)
40 |
41 | @staticmethod
42 | def _get_options(r):
43 | soup = BeautifulSoup(r.text, 'lxml')
44 | options = [h.text for h in soup.find_all('a', href=True)
45 | if h.text.endswith(('.zip', 'tar.gz'))]
46 | return options
47 |
48 | def _present_options(self):
49 | r = requests.get(self.url)
50 | options = self._get_options(r)
51 | print('Options:\n')
52 | for i, o in enumerate(options):
53 | print("{0}: {1}".format(i, o))
54 | choice = input("\nPlease enter the number of the "
55 | "dataset above you wish to download:")
56 | return options[int(choice)]
57 |
58 | def _download_data(self, dataset_url, save_path):
59 | if not isdir(save_path):
60 | os.makedirs(save_path)
61 |
62 | base = basename(dataset_url)
63 | temp_save_path = join(save_path, base)
64 |
65 | with open(temp_save_path, "wb") as f:
66 | r = requests.get(dataset_url)
67 | f.write(r.content)
68 |
69 | if base.endswith('.tar.gz'):
70 | obj = tarfile.open(temp_save_path)
71 | elif base.endswith('.zip'):
72 | obj = ZipFile(temp_save_path, 'r')
73 | else:
74 | raise ValueError("Unknown File Type: {0}.".format(base))
75 |
76 | self._print("Unpacking Data...")
77 | obj.extractall(save_path)
78 | obj.close()
79 | os.remove(temp_save_path)
80 |
81 | def get(self, save_path, dataset=None):
82 | """
83 |
84 | Download a dataset.
85 |
86 | Args:
87 | save_path : str
88 | A directory to save the data to.
89 | dataset : str, optional
90 | A specific dataset to download.
91 | Note: this must include the file extension.
92 | If None, options will be presented for you
93 | to choose from.
94 |
95 | Returns:
96 | save_path_full : str
97 | The absolute path to the downloaded data.
98 |
99 | """
100 | if dataset is None:
101 | selected_dataset = self._present_options()
102 | else:
103 | selected_dataset = dataset
104 |
105 | save_path_full = join(save_path, selected_dataset.split('.')[0])
106 |
107 | if isdir(save_path_full):
108 | warn("\n'{0}' already exists. Voiding Download.".format(
109 | save_path_full))
110 | else:
111 | self._print('Downloading Data...')
112 | url = "{0}/{1}".format(self.url, selected_dataset)
113 | self._download_data(url, save_path=save_path)
114 |
115 | return abspath(save_path_full)
116 |
--------------------------------------------------------------------------------
/src/train_main_ddvo.py:
--------------------------------------------------------------------------------
1 | import torch
2 | from torch import optim
3 | import matplotlib.pyplot as plt
4 | import torchvision
5 | import numpy as np
6 | from torch.autograd import Variable
7 | from torch.utils.data import DataLoader
8 | import scipy.io as sio
9 | import os
10 |
11 | from LKVOLearner import LKVOLearner
12 | from KITTIdataset import KITTIdataset
13 |
14 | from collections import OrderedDict
15 | from options.train_options import TrainOptions
16 | from util.visualizer import Visualizer
17 |
18 | from timeit import default_timer as timer
19 | # data_root_path = '/newfoundland/chaoyang/SfMLearner/data_kitti'
20 |
21 | opt = TrainOptions().parse()
22 | img_size = [opt.imH, opt.imW]
23 |
24 | visualizer = Visualizer(opt)
25 |
26 | dataset = KITTIdataset(data_root_path=opt.dataroot, img_size=img_size, bundle_size=3)
27 | dataloader = DataLoader(dataset, batch_size=opt.batchSize,
28 | shuffle=True, num_workers=opt.nThreads, pin_memory=True)
29 |
30 | gpu_ids = list(range(opt.batchSize))
31 |
32 |
33 | lkvolearner = LKVOLearner(img_size=img_size, ref_frame_idx=1, lambda_S=opt.lambda_S, gpu_ids = gpu_ids, smooth_term = opt.smooth_term, use_ssim=opt.use_ssim)
34 | lkvolearner.init_weights()
35 |
36 |
37 | if opt.which_epoch >= 0:
38 | print("load pretrained model")
39 | lkvolearner.load_model(os.path.join(opt.checkpoints_dir, '%s_model.pth' % (opt.which_epoch)))
40 |
41 | lkvolearner.cuda()
42 |
43 | ref_frame_idx = 1
44 |
45 |
46 | def vis_depthmap(input):
47 | x = (input-input.min()) * (255/(input.max()-input.min()+.00001))
48 | return x.unsqueeze(2).repeat(1, 1, 3)
49 |
50 |
51 |
52 |
53 |
54 | optimizer = optim.Adam(lkvolearner.get_parameters(), lr=.0001)
55 |
56 | step_num = 0
57 |
58 |
59 |
60 | for epoch in range(max(0, opt.which_epoch), opt.epoch_num+1):
61 | t = timer()
62 | for ii, data in enumerate(dataloader):
63 | optimizer.zero_grad()
64 | frames = Variable(data[0].float().cuda())
65 | camparams = Variable(data[1])
66 | cost, photometric_cost, smoothness_cost, frames, inv_depths = \
67 | lkvolearner.forward(frames, camparams, max_lk_iter_num=opt.max_lk_iter_num)
68 | # print(frames.size())
69 | # print(inv_depths.size())
70 | cost_ = cost.data.cpu()
71 | inv_depths_mean = inv_depths.mean().data.cpu().numpy()
72 | # if np.isnan(cost_.numpy()) or np.isinf(cost_.numpy()) or inv_depths_mean<1 or inv_depths_mean>7:
73 | # # lkvolearner.save_model(os.path.join(opt.checkpoints_dir, '%s_model.pth' % (epoch)))
74 | # print("detect nan or inf-----!!!!! %f" %(inv_depths_mean))
75 | # continue
76 |
77 | # print(cost)
78 | # print(inv_depth_pyramid)
79 | cost.backward()
80 | optimizer.step()
81 |
82 | step_num+=1
83 |
84 | if np.mod(step_num, opt.print_freq)==0:
85 | elapsed_time = timer()-t
86 | print('%s: %s / %s, ... elapsed time: %f (s)' % (epoch, step_num, int(len(dataset)/opt.batchSize), elapsed_time))
87 | print(inv_depths_mean)
88 | t = timer()
89 | visualizer.plot_current_errors(step_num, 1, opt,
90 | OrderedDict([('photometric_cost', photometric_cost.data.cpu()[0]),
91 | ('smoothness_cost', smoothness_cost.data.cpu()[0]),
92 | ('cost', cost.data.cpu()[0])]))
93 |
94 | if np.mod(step_num, opt.display_freq)==0:
95 | # frame_vis = frames.data[:,1,:,:,:].permute(0,2,3,1).contiguous().view(-1,opt.imW, 3).cpu().numpy().astype(np.uint8)
96 | # depth_vis = vis_depthmap(inv_depths.data[:,1,:,:].contiguous().view(-1,opt.imW).cpu()).numpy().astype(np.uint8)
97 | frame_vis = frames.data.permute(1,2,0).contiguous().cpu().numpy().astype(np.uint8)
98 | depth_vis = vis_depthmap(inv_depths.data.cpu()).numpy().astype(np.uint8)
99 | visualizer.display_current_results(
100 | OrderedDict([('%s frame' % (opt.name), frame_vis),
101 | ('%s inv_depth' % (opt.name), depth_vis)]),
102 | epoch)
103 | sio.savemat(os.path.join(opt.checkpoints_dir, 'depth_%s.mat' % (step_num)),
104 | {'D': inv_depths.data.cpu().numpy(),
105 | 'I': frame_vis})
106 |
107 | if np.mod(step_num, opt.save_latest_freq)==0:
108 | print("cache model....")
109 | lkvolearner.save_model(os.path.join(opt.checkpoints_dir, '%s_model.pth' % (epoch)))
110 | lkvolearner.cuda()
111 | print('..... saved')
112 |
--------------------------------------------------------------------------------
/src/train_main_posenet.py:
--------------------------------------------------------------------------------
1 | import torch
2 | from torch import optim
3 | import matplotlib.pyplot as plt
4 | import torchvision
5 | import numpy as np
6 | from torch.autograd import Variable
7 | from torch.utils.data import DataLoader
8 | import scipy.io as sio
9 | import os
10 |
11 | from SfMLearner import SfMLearner
12 | from KITTIdataset import KITTIdataset
13 | # from KCSdataset import KCSdataset
14 |
15 | from collections import OrderedDict
16 | from options.train_options import TrainOptions
17 | from util.visualizer import Visualizer
18 |
19 | from timeit import default_timer as timer
20 | # data_root_path = '/newfoundland/chaoyang/SfMLearner/data_kitti'
21 |
22 | opt = TrainOptions().parse()
23 | img_size = [opt.imH, opt.imW]
24 |
25 | visualizer = Visualizer(opt)
26 |
27 | dataset = KITTIdataset(data_root_path=opt.dataroot, img_size=img_size, bundle_size=3)
28 | # dataset = KCSdataset(img_size=img_size, bundle_size=3)
29 | dataloader = DataLoader(dataset, batch_size=opt.batchSize,
30 | shuffle=True, num_workers=opt.nThreads, pin_memory=True)
31 |
32 | gpu_ids = list(range(opt.batchSize))
33 |
34 |
35 | sfmlearner = SfMLearner(img_size=img_size, ref_frame_idx=1, lambda_S=opt.lambda_S, gpu_ids = gpu_ids, smooth_term = opt.smooth_term, use_ssim=opt.use_ssim)
36 | sfmlearner.init_weights()
37 |
38 |
39 | if opt.which_epoch >= 0:
40 | print("load pretrained model")
41 | sfmlearner.load_model(os.path.join(opt.checkpoints_dir, '%s' % (opt.which_epoch)))
42 |
43 | sfmlearner.cuda()
44 |
45 | ref_frame_idx = 1
46 |
47 |
48 | def vis_depthmap(input):
49 | x = (input-input.min()) * (255/(input.max()-input.min()+.00001))
50 | return x.unsqueeze(2).repeat(1, 1, 3)
51 |
52 |
53 | optimizer = optim.Adam(sfmlearner.get_parameters(), lr=.0001)
54 |
55 | step_num = 0
56 |
57 |
58 |
59 | for epoch in range(max(0, opt.which_epoch), opt.epoch_num+1):
60 | t = timer()
61 | for ii, data in enumerate(dataloader):
62 | optimizer.zero_grad()
63 | frames = Variable(data[0].float().cuda())
64 | camparams = Variable(data[1])
65 | cost, photometric_cost, smoothness_cost, frames, inv_depths, _ = \
66 | sfmlearner.forward(frames, camparams)
67 | # print(frames.size())
68 | # print(inv_depths.size())
69 | cost_ = cost.data.cpu()
70 | inv_depths_mean = inv_depths.mean().data.cpu().numpy()
71 | # if np.isnan(cost_.numpy()) or np.isinf(cost_.numpy()) or inv_depths_mean<1 or inv_depths_mean>7:
72 | # # lkvolearner.save_model(os.path.join(opt.checkpoints_dir, '%s_model.pth' % (epoch)))
73 | # print("detect nan or inf-----!!!!! %f" %(inv_depths_mean))
74 | # continue
75 |
76 | # print(cost)
77 | # print(inv_depth_pyramid)
78 | cost.backward()
79 | optimizer.step()
80 |
81 | step_num+=1
82 |
83 | if np.mod(step_num, opt.print_freq)==0:
84 | elapsed_time = timer()-t
85 | print('%s: %s / %s, ... elapsed time: %f (s)' % (epoch, step_num, int(len(dataset)/opt.batchSize), elapsed_time))
86 | print(inv_depths_mean)
87 | t = timer()
88 | visualizer.plot_current_errors(step_num, 1, opt,
89 | OrderedDict([('photometric_cost', photometric_cost.data.cpu()[0]),
90 | ('smoothness_cost', smoothness_cost.data.cpu()[0]),
91 | ('cost', cost.data.cpu()[0])]))
92 |
93 | if np.mod(step_num, opt.display_freq)==0:
94 | # frame_vis = frames.data[:,1,:,:,:].permute(0,2,3,1).contiguous().view(-1,opt.imW, 3).cpu().numpy().astype(np.uint8)
95 | # depth_vis = vis_depthmap(inv_depths.data[:,1,:,:].contiguous().view(-1,opt.imW).cpu()).numpy().astype(np.uint8)
96 | frame_vis = frames.data.permute(1,2,0).contiguous().cpu().numpy().astype(np.uint8)
97 | depth_vis = vis_depthmap(inv_depths.data.cpu()).numpy().astype(np.uint8)
98 | visualizer.display_current_results(
99 | OrderedDict([('%s frame' % (opt.name), frame_vis),
100 | ('%s inv_depth' % (opt.name), depth_vis)]),
101 | epoch)
102 | sio.savemat(os.path.join(opt.checkpoints_dir, 'depth_%s.mat' % (step_num)),
103 | {'D': inv_depths.data.cpu().numpy(),
104 | 'I': frame_vis})
105 |
106 | if np.mod(step_num, opt.save_latest_freq)==0:
107 | print("cache model....")
108 | sfmlearner.save_model(os.path.join(opt.checkpoints_dir, '%s' % (epoch)))
109 | sfmlearner.cuda()
110 | print('..... saved')
111 |
--------------------------------------------------------------------------------
/src/train_main_finetune.py:
--------------------------------------------------------------------------------
1 | import torch
2 | from torch import optim
3 | import matplotlib.pyplot as plt
4 | import torchvision
5 | import numpy as np
6 | from torch.autograd import Variable
7 | from torch.utils.data import DataLoader
8 | import scipy.io as sio
9 | import os
10 |
11 | from LKVOLearnerFinetune import LKVOLearner
12 | from KITTIdataset import KITTIdataset
13 |
14 | from collections import OrderedDict
15 | from options.train_options import TrainOptions
16 | from util.visualizer import Visualizer
17 |
18 | from timeit import default_timer as timer
19 | # data_root_path = '/newfoundland/chaoyang/SfMLearner/data_kitti'
20 |
21 | opt = TrainOptions().parse()
22 | img_size = [opt.imH, opt.imW]
23 |
24 | visualizer = Visualizer(opt)
25 |
26 | dataset = KITTIdataset(data_root_path=opt.dataroot, img_size=img_size, bundle_size=3)
27 | dataloader = DataLoader(dataset, batch_size=opt.batchSize,
28 | shuffle=True, num_workers=opt.nThreads, pin_memory=True)
29 |
30 | gpu_ids = list(range(opt.batchSize))
31 |
32 |
33 | lkvolearner = LKVOLearner(img_size=img_size, ref_frame_idx=1, lambda_S=opt.lambda_S, gpu_ids = gpu_ids,
34 | smooth_term = opt.smooth_term, use_ssim=opt.use_ssim)
35 | lkvolearner.init_weights()
36 |
37 |
38 | if opt.which_epoch >= 0:
39 | print("load last checkpoint")
40 | lkvolearner.load_model(os.path.join(opt.checkpoints_dir, '%s_model.pth' % (opt.which_epoch)),
41 | os.path.join(opt.checkpoints_dir, 'pose_net.pth'))
42 | else:
43 | print("load pretrained models")
44 | lkvolearner.load_model(os.path.join(opt.checkpoints_dir, 'depth_net.pth'),
45 | os.path.join(opt.checkpoints_dir, 'pose_net.pth'))
46 |
47 | lkvolearner.cuda()
48 |
49 | ref_frame_idx = 1
50 |
51 |
52 | def vis_depthmap(input):
53 | x = (input-input.min()) * (255/(input.max()-input.min()+.00001))
54 | return x.unsqueeze(2).repeat(1, 1, 3)
55 |
56 |
57 |
58 |
59 |
60 | optimizer = optim.Adam(lkvolearner.get_parameters(), lr=.0001)
61 |
62 | step_num = 0
63 |
64 |
65 |
66 | for epoch in range(max(0, opt.which_epoch), opt.epoch_num+1):
67 | t = timer()
68 | for ii, data in enumerate(dataloader):
69 | optimizer.zero_grad()
70 | frames = Variable(data[0].float().cuda())
71 | camparams = Variable(data[1])
72 | cost, photometric_cost, smoothness_cost, frames, inv_depths = \
73 | lkvolearner.forward(frames, camparams, max_lk_iter_num=opt.max_lk_iter_num, lk_level=opt.lk_level)
74 | # print(frames.size())
75 | # print(inv_depths.size())
76 | cost_ = cost.data.cpu()
77 | inv_depths_mean = inv_depths.mean().data.cpu().numpy()
78 | # if np.isnan(cost_.numpy()) or np.isinf(cost_.numpy()) or inv_depths_mean<1 or inv_depths_mean>7:
79 | # # lkvolearner.save_model(os.path.join(opt.checkpoints_dir, '%s_model.pth' % (epoch)))
80 | # print("detect nan or inf-----!!!!! %f" %(inv_depths_mean))
81 | # continue
82 |
83 | # print(cost)
84 | # print(inv_depth_pyramid)
85 | cost.backward()
86 | optimizer.step()
87 |
88 | step_num+=1
89 |
90 | if np.mod(step_num, opt.print_freq)==0:
91 | elapsed_time = timer()-t
92 | print('%s: %s / %s, ... elapsed time: %f (s)' % (epoch, step_num, int(len(dataset)/opt.batchSize), elapsed_time))
93 | print(inv_depths_mean)
94 | t = timer()
95 | visualizer.plot_current_errors(step_num, 1, opt,
96 | OrderedDict([('photometric_cost', photometric_cost.data.cpu()[0]),
97 | ('smoothness_cost', smoothness_cost.data.cpu()[0]),
98 | ('cost', cost.data.cpu()[0])]))
99 |
100 | if np.mod(step_num, opt.display_freq)==0:
101 | # frame_vis = frames.data[:,1,:,:,:].permute(0,2,3,1).contiguous().view(-1,opt.imW, 3).cpu().numpy().astype(np.uint8)
102 | # depth_vis = vis_depthmap(inv_depths.data[:,1,:,:].contiguous().view(-1,opt.imW).cpu()).numpy().astype(np.uint8)
103 | frame_vis = frames.data.permute(1,2,0).contiguous().cpu().numpy().astype(np.uint8)
104 | depth_vis = vis_depthmap(inv_depths.data.cpu()).numpy().astype(np.uint8)
105 | visualizer.display_current_results(
106 | OrderedDict([('%s frame' % (opt.name), frame_vis),
107 | ('%s inv_depth' % (opt.name), depth_vis)]),
108 | epoch)
109 | sio.savemat(os.path.join(opt.checkpoints_dir, 'depth_%s.mat' % (step_num)),
110 | {'D': inv_depths.data.cpu().numpy(),
111 | 'I': frame_vis})
112 |
113 | if np.mod(step_num, opt.save_latest_freq)==0:
114 | print("cache model....")
115 | lkvolearner.save_model(os.path.join(opt.checkpoints_dir, '%s_model.pth' % (epoch)))
116 | lkvolearner.cuda()
117 | print('..... saved')
118 |
--------------------------------------------------------------------------------
/src/ImagePyramid.py:
--------------------------------------------------------------------------------
1 | # from torchvision.transforms import Scale # it appears torchvision has some bugs, work on that latter
2 | import torch.nn as nn
3 | from torch.nn import AvgPool2d
4 | from torch.nn.functional import conv2d
5 | from torch.autograd import Variable
6 | from timeit import default_timer as timer
7 | import torch
8 | import numpy as np
9 |
10 | import matplotlib.pyplot as plt
11 | import scipy.io as sio
12 | import os
13 |
14 |
15 |
16 | class ImageSmoothLayer(nn.Module):
17 | def __init__(self, chan):
18 | super(ImageSmoothLayer, self).__init__()
19 | F = torch.FloatTensor([[0.0751, 0.1238, 0.0751],
20 | [0.1238, 0.2042, 0.1238],
21 | [0.0751, 0.1238, 0.0751]]).view(1, 1, 3, 3)
22 | self.register_buffer('smooth_kernel', F)
23 | if chan>1:
24 | f = F
25 | F = torch.zeros(chan, chan, 3, 3)
26 | for i in range(chan):
27 | F[i, i, :, :] = f
28 | self.register_buffer('smooth_kernel_K', F)
29 | self.reflection_pad_func = torch.nn.ReflectionPad2d(1)
30 |
31 | def forward(self, input):
32 | output_dim = input.dim()
33 | output_size = input.size()
34 | if output_dim==2:
35 | F = self.smooth_kernel
36 | input = input.unsqueeze(0).unsqueeze(0)
37 | elif output_dim==3:
38 | F = self.smooth_kernel
39 | input = input.unsqueeze(1)
40 | else:
41 | F = self.smooth_kernel_K
42 |
43 | x = self.reflection_pad_func(input)
44 |
45 | x = conv2d(input=x,
46 | weight=Variable(F),
47 | stride=1,
48 | padding=0)
49 |
50 | if output_dim==2:
51 | x = x.squeeze(0).squeeze(0)
52 | elif output_dim==3:
53 | x = x.squeeze(1)
54 |
55 | return x
56 |
57 |
58 | class ImagePyramidLayer(nn.Module):
59 | def __init__(self, chan, pyramid_layer_num):
60 | super(ImagePyramidLayer, self).__init__()
61 | self.pyramid_layer_num = pyramid_layer_num
62 | F = torch.FloatTensor([[0.0751, 0.1238, 0.0751],
63 | [0.1238, 0.2042, 0.1238],
64 | [0.0751, 0.1238, 0.0751]]).view(1, 1, 3, 3)
65 | self.register_buffer('smooth_kernel', F)
66 | if chan>1:
67 | f = F
68 | F = torch.zeros(chan, chan, 3, 3)
69 | for i in range(chan):
70 | F[i, i, :, :] = f
71 | self.register_buffer('smooth_kernel_K', F)
72 | self.avg_pool_func = torch.nn.AvgPool2d(kernel_size=2, stride=2, padding=0)
73 | self.reflection_pad_func = torch.nn.ReflectionPad2d(1)
74 |
75 |
76 | def downsample(self, input):
77 | output_dim = input.dim()
78 | output_size = input.size()
79 | if output_dim==2:
80 | F = self.smooth_kernel
81 | input = input.unsqueeze(0).unsqueeze(0)
82 | elif output_dim==3:
83 | F = self.smooth_kernel
84 | input = input.unsqueeze(1)
85 | else:
86 | F = self.smooth_kernel_K
87 |
88 | x = self.reflection_pad_func(input)
89 |
90 | x = conv2d(input=x,
91 | weight=Variable(F),
92 | stride=1,
93 | padding=0)
94 | # remove here if not work out
95 | padding = [0, int(np.mod(input.size(-1), 2)), 0, int(np.mod(input.size(-2), 2))]
96 | x = torch.nn.ReplicationPad2d(padding)(x)
97 | # -----
98 | x = self.avg_pool_func(x)
99 |
100 | if output_dim==2:
101 | x = x.squeeze(0).squeeze(0)
102 | elif output_dim==3:
103 | x = x.squeeze(1)
104 |
105 | return x
106 |
107 |
108 | def forward(self, input, do_detach=True):
109 | pyramid = [input]
110 | for i in range(self.pyramid_layer_num-1):
111 | img_d = self.downsample(pyramid[i])
112 | if isinstance(img_d, Variable) and do_detach:
113 | img_d = img_d.detach()
114 | pyramid.append(img_d)
115 | assert(np.ceil(pyramid[i].size(-1)/2) == img_d.size(-1))
116 | return pyramid
117 |
118 |
119 | def get_coords(self, imH, imW):
120 | x_pyramid = [np.arange(imW)+.5]
121 | y_pyramid = [np.arange(imH)+.5]
122 | for i in range(self.pyramid_layer_num-1):
123 | offset = 2**i
124 | stride = 2**(i+1)
125 | x_pyramid.append(np.arange(offset, offset + stride*np.ceil(x_pyramid[i].shape[0]/2), stride))
126 | y_pyramid.append(np.arange(offset, offset + stride*np.ceil(y_pyramid[i].shape[0]/2), stride))
127 |
128 | return x_pyramid, y_pyramid
129 |
130 |
131 |
132 | if __name__ == "__main__":
133 | imH = 128
134 | imW = 416
135 | img = Variable(torch.randn(3, 128, 416))
136 | n = ImagePyramidLayer(3, 7)
137 | x_pyramid, y_pyramid = n.get_coords(imH, imW)
138 | t = timer()
139 | # pyramid, x_pyramid, y_pyramid = buildImagePyramid(Variable(torch.rand(1, 3, 256, 320)), 6)
140 | pyramid = n.forward(img)
141 | print(timer()-t)
142 |
143 | for i in range(n.pyramid_layer_num):
144 | print(x_pyramid[i].shape[0])
145 | print(y_pyramid[i].shape[0])
146 | print(pyramid[i].size())
147 | # print(pyramid)
148 |
--------------------------------------------------------------------------------
/src/util/visualizer.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import os
3 | import ntpath
4 | import time
5 | from . import util
6 | from . import html
7 |
8 | class Visualizer():
9 | def __init__(self, opt):
10 | # self.opt = opt
11 | self.display_id = opt.display_id
12 | self.use_html = opt.isTrain and not opt.no_html
13 | self.win_size = opt.display_winsize
14 | self.name = opt.name
15 | if self.display_id > 0:
16 | import visdom
17 | self.vis = visdom.Visdom(port = opt.display_port)
18 | self.display_single_pane_ncols = opt.display_single_pane_ncols
19 |
20 | if self.use_html:
21 | self.web_dir = os.path.join(opt.checkpoints_dir, opt.name, 'web')
22 | self.img_dir = os.path.join(self.web_dir, 'images')
23 | print('create web directory %s...' % self.web_dir)
24 | util.mkdirs([self.web_dir, self.img_dir])
25 | self.log_name = os.path.join(opt.checkpoints_dir, opt.name, 'loss_log.txt')
26 | with open(self.log_name, "a") as log_file:
27 | now = time.strftime("%c")
28 | log_file.write('================ Training Loss (%s) ================\n' % now)
29 |
30 | # |visuals|: dictionary of images to display or save
31 | def display_current_results(self, visuals, epoch):
32 | if self.display_id > 0: # show images in the browser
33 | if self.display_single_pane_ncols > 0:
34 | h, w = next(iter(visuals.values())).shape[:2]
35 | table_css = """""" % (w, h)
39 | ncols = self.display_single_pane_ncols
40 | title = self.name
41 | label_html = ''
42 | label_html_row = ''
43 | nrows = int(np.ceil(len(visuals.items()) / ncols))
44 | images = []
45 | idx = 0
46 | for label, image_numpy in visuals.items():
47 | label_html_row += '
%s | ' % label
48 | images.append(image_numpy.transpose([2, 0, 1]))
49 | idx += 1
50 | if idx % ncols == 0:
51 | label_html += '%s
' % label_html_row
52 | label_html_row = ''
53 | white_image = np.ones_like(image_numpy.transpose([2, 0, 1]))*255
54 | while idx % ncols != 0:
55 | images.append(white_image)
56 | label_html_row += ' | '
57 | idx += 1
58 | if label_html_row != '':
59 | label_html += '%s
' % label_html_row
60 | # pane col = image row
61 | self.vis.images(images, nrow=ncols, win=self.display_id + 1,
62 | padding=2, opts=dict(title=title + ' images'))
63 | label_html = '' % label_html
64 | self.vis.text(table_css + label_html, win = self.display_id + 2,
65 | opts=dict(title=title + ' labels'))
66 | else:
67 | idx = 1
68 | for label, image_numpy in visuals.items():
69 | #image_numpy = np.flipud(image_numpy)
70 | self.vis.image(image_numpy.transpose([2,0,1]), opts=dict(title=label),
71 | win=self.display_id + idx)
72 | idx += 1
73 |
74 | if self.use_html: # save images to a html file
75 | for label, image_numpy in visuals.items():
76 | img_path = os.path.join(self.img_dir, 'epoch%.3d_%s.png' % (epoch, label))
77 | util.save_image(image_numpy, img_path)
78 | # update website
79 | webpage = html.HTML(self.web_dir, 'Experiment name = %s' % self.name, reflesh=1)
80 | for n in range(epoch, 0, -1):
81 | webpage.add_header('epoch [%d]' % n)
82 | ims = []
83 | txts = []
84 | links = []
85 |
86 | for label, image_numpy in visuals.items():
87 | img_path = 'epoch%.3d_%s.png' % (n, label)
88 | ims.append(img_path)
89 | txts.append(label)
90 | links.append(img_path)
91 | webpage.add_images(ims, txts, links, width=self.win_size)
92 | webpage.save()
93 |
94 | # errors: dictionary of error labels and values
95 | def plot_current_errors(self, epoch, counter_ratio, opt, errors):
96 | if not hasattr(self, 'plot_data'):
97 | self.plot_data = {'X':[],'Y':[], 'legend':list(errors.keys())}
98 | self.plot_data['X'].append(epoch + counter_ratio)
99 | self.plot_data['Y'].append([errors[k] for k in self.plot_data['legend']])
100 | self.vis.line(
101 | X=np.stack([np.array(self.plot_data['X'])]*len(self.plot_data['legend']),1),
102 | Y=np.array(self.plot_data['Y']),
103 | opts={
104 | 'title': self.name + ' loss over time',
105 | 'legend': self.plot_data['legend'],
106 | 'xlabel': 'epoch',
107 | 'ylabel': 'loss'},
108 | win=self.display_id)
109 |
110 | # errors: same format as |errors| of plotCurrentErrors
111 | def print_current_errors(self, epoch, i, errors, t):
112 | message = '(epoch: %d, iters: %d, time: %.3f) ' % (epoch, i, t)
113 | for k, v in errors.items():
114 | message += '%s: %.3f ' % (k, v)
115 |
116 | print(message)
117 | with open(self.log_name, "a") as log_file:
118 | log_file.write('%s\n' % message)
119 |
120 | # save image to the disk
121 | def save_images(self, webpage, visuals, image_path):
122 | image_dir = webpage.get_image_dir()
123 | short_path = ntpath.basename(image_path[0])
124 | name = os.path.splitext(short_path)[0]
125 |
126 | webpage.add_header(name)
127 | ims = []
128 | txts = []
129 | links = []
130 |
131 | for label, image_numpy in visuals.items():
132 | image_name = '%s_%s.png' % (name, label)
133 | save_path = os.path.join(image_dir, image_name)
134 | util.save_image(image_numpy, save_path)
135 |
136 | ims.append(image_name)
137 | txts.append(label)
138 | links.append(image_name)
139 | webpage.add_images(ims, txts, links, width=self.win_size)
140 |
--------------------------------------------------------------------------------
/src/LKVOLearnerFinetune.py:
--------------------------------------------------------------------------------
1 | from DirectVOLayer import DirectVO
2 | from networks import VggDepthEstimator, PoseNet
3 | from ImagePyramid import ImagePyramidLayer
4 | import torch.nn as nn
5 | import torch
6 | import numpy as np
7 | from torch.autograd import Variable
8 | from timeit import default_timer as timer
9 |
10 | class FlipLR(nn.Module):
11 | def __init__(self, imW, dim_w):
12 | super(FlipLR, self).__init__()
13 | inv_indices = torch.arange(imW-1, -1, -1).long()
14 | self.register_buffer('inv_indices', inv_indices)
15 | self.dim_w = dim_w
16 |
17 |
18 | def forward(self, input):
19 | return input.index_select(self.dim_w, Variable(self.inv_indices))
20 |
21 |
22 |
23 | class LKVOLearner(nn.Module):
24 | def __init__(self, img_size=[128, 416], ref_frame_idx=1, lambda_S=.5, use_ssim=True, smooth_term = 'lap', gpu_ids=[0]):
25 | super(LKVOLearner, self).__init__()
26 | self.lkvo = nn.DataParallel(LKVOKernel(img_size, smooth_term = smooth_term), device_ids=gpu_ids)
27 | self.ref_frame_idx = ref_frame_idx
28 | self.lambda_S = lambda_S
29 | self.use_ssim = use_ssim
30 |
31 | def forward(self, frames, camparams, max_lk_iter_num=10, lk_level=1):
32 | cost, photometric_cost, smoothness_cost, ref_frame, ref_inv_depth \
33 | = self.lkvo.forward(frames, camparams, self.ref_frame_idx, self.lambda_S, max_lk_iter_num=max_lk_iter_num, use_ssim=self.use_ssim, lk_level=lk_level)
34 | return cost.mean(), photometric_cost.mean(), smoothness_cost.mean(), ref_frame, ref_inv_depth
35 |
36 | def save_model(self, file_path):
37 | torch.save(self.cpu().lkvo.module.depth_net.state_dict(),
38 | file_path)
39 | self.cuda()
40 |
41 | def load_model(self, depth_net_file_path, pose_net_file_path):
42 | self.lkvo.module.depth_net.load_state_dict(torch.load(depth_net_file_path))
43 | self.lkvo.module.pose_net.load_state_dict(torch.load(pose_net_file_path))
44 |
45 | def init_weights(self):
46 | self.lkvo.module.depth_net.init_weights()
47 |
48 | def get_parameters(self):
49 | return self.lkvo.module.depth_net.parameters()
50 |
51 |
52 |
53 | class LKVOKernel(nn.Module):
54 | """
55 | only support single training isinstance
56 | """
57 | def __init__(self, img_size=[128, 416], smooth_term = 'lap'):
58 | super(LKVOKernel, self).__init__()
59 | self.img_size = img_size
60 | self.fliplr_func = FlipLR(imW=img_size[1], dim_w=3)
61 | self.vo = DirectVO(imH=img_size[0], imW=img_size[1], pyramid_layer_num=4)
62 | self.pose_net = PoseNet(3)
63 | self.depth_net = VggDepthEstimator(img_size)
64 | self.pyramid_func = ImagePyramidLayer(chan=1, pyramid_layer_num=4)
65 | self.smooth_term = smooth_term
66 |
67 |
68 | def forward(self, frames, camparams, ref_frame_idx, lambda_S=.5, do_data_augment=True, use_ssim=True, max_lk_iter_num=10, lk_level=1):
69 | assert(frames.size(0) == 1 and frames.dim() == 5)
70 | frames = frames.squeeze(0)
71 | camparams = camparams.squeeze(0).data
72 |
73 |
74 | if do_data_augment:
75 | if np.random.rand()>.5:
76 | # print("fliplr")
77 | frames = self.fliplr_func(frames)
78 | camparams[2] = self.img_size[1] - camparams[2]
79 | # camparams[5] = self.img_size[0] - camparams[5]
80 |
81 | bundle_size = frames.size(0)
82 | src_frame_idx = tuple(range(0,ref_frame_idx)) + tuple(range(ref_frame_idx+1,bundle_size))
83 | # ref_frame = frames[ref_frame_idx, :, :, :]
84 | # src_frames = frames[src_frame_idx, :, :, :]
85 | frames_pyramid = self.vo.pyramid_func(frames)
86 | ref_frame_pyramid = [frame[ref_frame_idx, :, :, :] for frame in frames_pyramid]
87 | src_frames_pyramid = [frame[src_frame_idx, :, :, :] for frame in frames_pyramid]
88 |
89 |
90 | self.vo.setCamera(fx=camparams[0], cx=camparams[2],
91 | fy=camparams[4], cy=camparams[5])
92 |
93 | inv_depth_pyramid = self.depth_net.forward((frames-127)/127)
94 | inv_depth_mean_ten = inv_depth_pyramid[0].mean()*0.1
95 |
96 | inv_depth_norm_pyramid = [depth/inv_depth_mean_ten for depth in inv_depth_pyramid]
97 | inv_depth0_pyramid = self.pyramid_func(inv_depth_norm_pyramid[0], do_detach=False)
98 | ref_inv_depth_pyramid = [depth[ref_frame_idx, :, :] for depth in inv_depth_norm_pyramid]
99 | ref_inv_depth0_pyramid = [depth[ref_frame_idx, :, :] for depth in inv_depth0_pyramid]
100 | src_inv_depth_pyramid = [depth[src_frame_idx, :, :] for depth in inv_depth_norm_pyramid]
101 | src_inv_depth0_pyramid = [depth[src_frame_idx, :, :] for depth in inv_depth0_pyramid]
102 |
103 | self.vo.init(ref_frame_pyramid=ref_frame_pyramid, inv_depth_pyramid=ref_inv_depth0_pyramid)
104 | # init_pose with pose CNN
105 | p = self.pose_net.forward((frames.view(1, -1, frames.size(2), frames.size(3))-127) / 127)
106 | rot_mat_batch = self.vo.twist2mat_batch_func(p[0,:,0:3]).contiguous()
107 | trans_batch = p[0,:,3:6].contiguous()#*inv_depth_mean_ten
108 | # fine tune pose with direct VO
109 | rot_mat_batch, trans_batch = self.vo.update_with_init_pose(src_frames_pyramid[0:lk_level], max_itr_num=max_lk_iter_num, rot_mat_batch=rot_mat_batch, trans_batch=trans_batch)
110 | # rot_mat_batch, trans_batch = \
111 | # self.vo.forward(ref_frame_pyramid, src_frames_pyramid, ref_inv_depth0_pyramid, max_itr_num=max_lk_iter_num)
112 |
113 | photometric_cost = self.vo.compute_phtometric_loss(self.vo.ref_frame_pyramid, src_frames_pyramid, ref_inv_depth_pyramid, src_inv_depth_pyramid, rot_mat_batch, trans_batch, levels=[0,1,2,3], use_ssim=use_ssim)
114 | smoothness_cost = self.vo.multi_scale_image_aware_smoothness_cost(inv_depth0_pyramid, frames_pyramid, levels=[2,3], type=self.smooth_term) \
115 | + self.vo.multi_scale_image_aware_smoothness_cost(inv_depth_norm_pyramid, frames_pyramid, levels=[2,3], type=self.smooth_term)
116 |
117 | cost = photometric_cost + lambda_S*smoothness_cost
118 | return cost, photometric_cost, smoothness_cost, self.vo.ref_frame_pyramid[0], ref_inv_depth0_pyramid[0]*inv_depth_mean_ten
119 |
120 |
121 | if __name__ == "__main__":
122 | from KITTIdataset import KITTIdataset
123 | from torch.utils.data import DataLoader
124 | from torch import optim
125 | from torch.autograd import Variable
126 |
127 | dataset = KITTIdataset()
128 | dataloader = DataLoader(dataset, batch_size=3,
129 | shuffle=True, num_workers=2, pin_memory=True)
130 | lkvolearner = LKVOLearner(gpu_ids = [0])
131 | def weights_init(m):
132 | classname = m.__class__.__name__
133 | if isinstance(m, torch.nn.Conv2d) or isinstance(m, torch.nn.ConvTranspose2d):
134 | # m.weight.data.normal_(0.0, 0.02)
135 | m.bias.data = torch.zeros(m.bias.data.size())
136 |
137 | lkvolearner.apply(weights_init)
138 | lkvolearner.cuda()
139 |
140 | optimizer = optim.Adam(lkvolearner.parameters(), lr=.0001)
141 | for ii, data in enumerate(dataloader):
142 | t = timer()
143 | optimizer.zero_grad()
144 | frames = Variable(data[0].float().cuda())
145 | # print(data[1])
146 | camparams = Variable(data[1])
147 | a = lkvolearner.forward(frames, camparams)
148 | print(timer()-t)
149 | # print(a)
150 |
--------------------------------------------------------------------------------
/src/SfMLearner.py:
--------------------------------------------------------------------------------
1 | from DirectVOLayer import DirectVO
2 | from networks import VggDepthEstimator, PoseNet, PoseExpNet
3 | from ImagePyramid import ImagePyramidLayer
4 | import torch.nn as nn
5 | import torch
6 | from torch.autograd import Variable
7 | import numpy as np
8 |
9 | import itertools
10 |
11 | from timeit import default_timer as timer
12 |
13 | class FlipLR(nn.Module):
14 | def __init__(self, imW, dim_w):
15 | super(FlipLR, self).__init__()
16 | inv_indices = torch.arange(imW-1, -1, -1).long()
17 | self.register_buffer('inv_indices', inv_indices)
18 | self.dim_w = dim_w
19 |
20 |
21 | def forward(self, input):
22 | return input.index_select(self.dim_w, Variable(self.inv_indices))
23 |
24 |
25 |
26 | class SfMLearner(nn.Module):
27 | def __init__(self, img_size=[128, 416], ref_frame_idx=1,
28 | lambda_S=.5, lambda_E=0.01, use_ssim=True, smooth_term = 'lap',
29 | use_expl_mask=False, gpu_ids=[0]):
30 | super(SfMLearner, self).__init__()
31 | self.sfmkernel = nn.DataParallel(SfMKernel(img_size, smooth_term = smooth_term, use_expl_mask=use_expl_mask),
32 | device_ids=gpu_ids)
33 | self.ref_frame_idx = ref_frame_idx
34 | self.lambda_S = lambda_S
35 | self.lambda_E = lambda_E
36 | self.use_ssim = use_ssim
37 | self.use_expl_mask = use_expl_mask
38 |
39 | def forward(self, frames, camparams, max_lk_iter_num=10):
40 | cost, photometric_cost, smoothness_cost, ref_frame, ref_inv_depth, ref_expl_mask \
41 | = self.sfmkernel.forward(frames, camparams, self.ref_frame_idx,
42 | self.lambda_S, self.lambda_E, use_ssim=self.use_ssim)
43 | return cost.mean(), photometric_cost.mean(), smoothness_cost.mean(), ref_frame, ref_inv_depth, ref_expl_mask
44 |
45 | def save_model(self, file_path):
46 | torch.save(self.cpu().sfmkernel.module.depth_net.state_dict(),
47 | file_path+'_depth_net.pth')
48 | torch.save(self.sfmkernel.module.pose_net.state_dict(),
49 | file_path+'_pose_net.pth')
50 | self.cuda()
51 |
52 | def load_model(self, file_path):
53 | self.sfmkernel.module.depth_net.load_state_dict(torch.load(file_path+'_depth_net.pth'))
54 | self.sfmkernel.module.pose_net.load_state_dict(torch.load(file_path+'_pose_net.pth'))
55 |
56 | def init_weights(self):
57 | self.sfmkernel.module.depth_net.init_weights()
58 |
59 | def get_parameters(self):
60 | return itertools.chain(self.sfmkernel.module.depth_net.parameters(),
61 | self.sfmkernel.module.pose_net.parameters())
62 |
63 |
64 |
65 | class SfMKernel(nn.Module):
66 | """
67 | only support single training isinstance
68 | """
69 | def __init__(self, img_size=[128, 416], smooth_term = 'lap', use_expl_mask=False):
70 | super(SfMKernel, self).__init__()
71 | self.img_size = img_size
72 | self.fliplr_func = FlipLR(imW=img_size[1], dim_w=3)
73 | self.vo = DirectVO(imH=img_size[0], imW=img_size[1], pyramid_layer_num=4)
74 | self.depth_net = VggDepthEstimator(img_size)
75 | if use_expl_mask:
76 | self.pose_net = PoseExpNet(3)
77 | else:
78 | self.pose_net = PoseNet(3)
79 | self.pyramid_func = ImagePyramidLayer(chan=1, pyramid_layer_num=4)
80 | self.smooth_term = smooth_term
81 | self.use_expl_mask = use_expl_mask
82 |
83 |
84 | def forward(self, frames, camparams, ref_frame_idx, lambda_S=.5, lambda_E=.01, do_data_augment=True, use_ssim=True):
85 | assert(frames.size(0) == 1 and frames.dim() == 5)
86 | frames = frames.squeeze(0)
87 | camparams = camparams.squeeze(0).data
88 |
89 |
90 | if do_data_augment:
91 | if np.random.rand()>.5:
92 | frames = self.fliplr_func(frames)
93 | camparams[2] = self.img_size[1] - camparams[2]
94 |
95 | bundle_size = frames.size(0)
96 | src_frame_idx = tuple(range(0,ref_frame_idx)) + tuple(range(ref_frame_idx+1,bundle_size))
97 | frames_pyramid = self.vo.pyramid_func(frames)
98 | ref_frame_pyramid = [frame[ref_frame_idx, :, :, :] for frame in frames_pyramid]
99 | src_frames_pyramid = [frame[src_frame_idx, :, :, :] for frame in frames_pyramid]
100 |
101 |
102 | self.vo.setCamera(fx=camparams[0], cx=camparams[2],
103 | fy=camparams[4], cy=camparams[5])
104 | self.vo.init_xy_pyramid(ref_frame_pyramid)
105 | if self.use_expl_mask:
106 | p, expl_mask_pyramid = self.pose_net.forward((frames.view(1, -1, frames.size(2), frames.size(3))-127) / 127)
107 | expl_mask_reg_cost = 0
108 | for mask in expl_mask_pyramid:
109 | expl_mask_reg_cost += mask.mean()
110 | ref_expl_mask_pyramid = [mask.squeeze(0)[ref_frame_idx, ...] for mask in expl_mask_pyramid]
111 | src_expl_mask_pyramid = [mask.squeeze(0)[src_frame_idx, ...] for mask in expl_mask_pyramid]
112 | expl_mask = ref_expl_mask_pyramid[0]
113 |
114 | else:
115 | p = self.pose_net.forward((frames.view(1, -1, frames.size(2), frames.size(3))-127) / 127)
116 | ref_expl_mask_pyramid = None
117 | src_expl_mask_pyramid = None
118 | expl_mask_reg_cost = 0
119 | expl_mask = None
120 |
121 | rot_mat_batch = self.vo.twist2mat_batch_func(p[0,:,0:3])
122 | trans_batch = p[0,:,3:6]
123 |
124 | inv_depth_pyramid = self.depth_net.forward((frames-127)/127)
125 | inv_depth_mean_ten = inv_depth_pyramid[0].mean()*0.1 #uncommment this to use normalization
126 |
127 | # normalize
128 | #trans_batch = trans_batch*inv_depth_mean_ten
129 | inv_depth_norm_pyramid = [depth/inv_depth_mean_ten for depth in inv_depth_pyramid]
130 |
131 | ref_inv_depth_pyramid = [depth[ref_frame_idx, :, :] for depth in inv_depth_norm_pyramid]
132 | src_inv_depth_pyramid = [depth[src_frame_idx, :, :] for depth in inv_depth_norm_pyramid]
133 |
134 | photometric_cost = self.vo.compute_phtometric_loss(
135 | ref_frame_pyramid,
136 | src_frames_pyramid,
137 | ref_inv_depth_pyramid,
138 | src_inv_depth_pyramid,
139 | rot_mat_batch, trans_batch,
140 | levels=[0,1,2,3], use_ssim=use_ssim,
141 | ref_expl_mask_pyramid=ref_expl_mask_pyramid,
142 | src_expl_mask_pyramid=src_expl_mask_pyramid)
143 | # compute smoothness smoothness loss
144 | # instead of directly compute the loss on the finest level, it's evaluated on the downsamples.
145 | inv_depth0_pyramid = self.pyramid_func(inv_depth_norm_pyramid[0], do_detach=False)
146 | smoothness_cost = self.vo.multi_scale_image_aware_smoothness_cost(inv_depth0_pyramid, frames_pyramid, levels=[2,3], type=self.smooth_term) \
147 | + self.vo.multi_scale_image_aware_smoothness_cost(inv_depth_norm_pyramid, frames_pyramid, levels=[2,3], type=self.smooth_term)
148 |
149 | cost = photometric_cost + lambda_S*smoothness_cost - lambda_E*expl_mask_reg_cost
150 |
151 | return cost, photometric_cost, smoothness_cost, ref_frame_pyramid[0], ref_inv_depth_pyramid[0]*inv_depth_mean_ten, expl_mask
152 |
--------------------------------------------------------------------------------
/src/LKVOLearner.py:
--------------------------------------------------------------------------------
1 | from DirectVOLayer import DirectVO
2 | from networks import VggDepthEstimator
3 | from ImagePyramid import ImagePyramidLayer
4 | import torch.nn as nn
5 | import torch
6 | import numpy as np
7 | from torch.autograd import Variable
8 |
9 | from timeit import default_timer as timer
10 |
11 | class FlipLR(nn.Module):
12 | def __init__(self, imW, dim_w):
13 | super(FlipLR, self).__init__()
14 | inv_indices = torch.arange(imW-1, -1, -1).long()
15 | self.register_buffer('inv_indices', inv_indices)
16 | self.dim_w = dim_w
17 |
18 |
19 | def forward(self, input):
20 | return input.index_select(self.dim_w, Variable(self.inv_indices))
21 |
22 |
23 |
24 | class LKVOLearner(nn.Module):
25 | def __init__(self, img_size=[128, 416], ref_frame_idx=1, lambda_S=.5, use_ssim=True, smooth_term = 'lap', gpu_ids=[0]):
26 | super(LKVOLearner, self).__init__()
27 | self.lkvo = nn.DataParallel(LKVOKernel(img_size, smooth_term = smooth_term), device_ids=gpu_ids)
28 | self.ref_frame_idx = ref_frame_idx
29 | self.lambda_S = lambda_S
30 | self.use_ssim = use_ssim
31 |
32 | def forward(self, frames, camparams, max_lk_iter_num=10):
33 | cost, photometric_cost, smoothness_cost, ref_frame, ref_inv_depth \
34 | = self.lkvo.forward(frames, camparams, self.ref_frame_idx, self.lambda_S, max_lk_iter_num=max_lk_iter_num, use_ssim=self.use_ssim)
35 | return cost.mean(), photometric_cost.mean(), smoothness_cost.mean(), ref_frame, ref_inv_depth
36 |
37 | def save_model(self, file_path):
38 | torch.save(self.cpu().lkvo.module.depth_net.state_dict(),
39 | file_path)
40 | self.cuda()
41 |
42 | def load_model(self, file_path):
43 | self.lkvo.module.depth_net.load_state_dict(torch.load(file_path))
44 |
45 | def init_weights(self):
46 | self.lkvo.module.depth_net.init_weights()
47 |
48 | def get_parameters(self):
49 | return self.lkvo.module.depth_net.parameters()
50 |
51 |
52 |
53 | class LKVOKernel(nn.Module):
54 | """
55 | only support single training isinstance
56 | """
57 | def __init__(self, img_size=[128, 416], smooth_term = 'lap'):
58 | super(LKVOKernel, self).__init__()
59 | self.img_size = img_size
60 | self.fliplr_func = FlipLR(imW=img_size[1], dim_w=3)
61 | self.vo = DirectVO(imH=img_size[0], imW=img_size[1], pyramid_layer_num=5)
62 | self.depth_net = VggDepthEstimator(img_size)
63 | self.pyramid_func = ImagePyramidLayer(chan=1, pyramid_layer_num=5)
64 | self.smooth_term = smooth_term
65 |
66 |
67 | def forward(self, frames, camparams, ref_frame_idx, lambda_S=.5, do_data_augment=True, use_ssim=True, max_lk_iter_num=10):
68 | assert(frames.size(0) == 1 and frames.dim() == 5)
69 | frames = frames.squeeze(0)
70 | camparams = camparams.squeeze(0).data
71 |
72 |
73 | if do_data_augment:
74 | if np.random.rand()>.5:
75 | # print("fliplr")
76 | frames = self.fliplr_func(frames)
77 | camparams[2] = self.img_size[1] - camparams[2]
78 | # camparams[5] = self.img_size[0] - camparams[5]
79 |
80 | bundle_size = frames.size(0)
81 | src_frame_idx = tuple(range(0,ref_frame_idx)) + tuple(range(ref_frame_idx+1,bundle_size))
82 | # ref_frame = frames[ref_frame_idx, :, :, :]
83 | # src_frames = frames[src_frame_idx, :, :, :]
84 | frames_pyramid = self.vo.pyramid_func(frames)
85 | ref_frame_pyramid = [frame[ref_frame_idx, :, :, :] for frame in frames_pyramid]
86 | src_frames_pyramid = [frame[src_frame_idx, :, :, :] for frame in frames_pyramid]
87 |
88 |
89 | self.vo.setCamera(fx=camparams[0], cx=camparams[2],
90 | fy=camparams[4], cy=camparams[5])
91 |
92 | inv_depth_pyramid = self.depth_net.forward((frames-127)/127)
93 | inv_depth_mean_ten = inv_depth_pyramid[0].mean()*0.1
94 | #
95 | # inv_depth0_pyramid = self.pyramid_func(inv_depth_pyramid[0], do_detach=False)
96 | # ref_inv_depth_pyramid = [depth[ref_frame_idx, :, :] for depth in inv_depth_pyramid]
97 | # ref_inv_depth0_pyramid = [depth[ref_frame_idx, :, :] for depth in inv_depth0_pyramid]
98 | # src_inv_depth_pyramid = [depth[src_frame_idx, :, :] for depth in inv_depth_pyramid]
99 | # src_inv_depth0_pyramid = [depth[src_frame_idx, :, :] for depth in inv_depth0_pyramid]
100 |
101 | inv_depth_norm_pyramid = [depth/inv_depth_mean_ten for depth in inv_depth_pyramid]
102 | inv_depth0_pyramid = self.pyramid_func(inv_depth_norm_pyramid[0], do_detach=False)
103 | ref_inv_depth_pyramid = [depth[ref_frame_idx, :, :] for depth in inv_depth_norm_pyramid]
104 | ref_inv_depth0_pyramid = [depth[ref_frame_idx, :, :] for depth in inv_depth0_pyramid]
105 | src_inv_depth_pyramid = [depth[src_frame_idx, :, :] for depth in inv_depth_norm_pyramid]
106 | src_inv_depth0_pyramid = [depth[src_frame_idx, :, :] for depth in inv_depth0_pyramid]
107 |
108 | rot_mat_batch, trans_batch = \
109 | self.vo.forward(ref_frame_pyramid, src_frames_pyramid, ref_inv_depth0_pyramid, max_itr_num=max_lk_iter_num)
110 | #
111 | # smoothness_cost = self.vo.multi_scale_smoothness_cost(inv_depth_pyramid)
112 | # smoothness_cost += self.vo.multi_scale_smoothness_cost(inv_depth0_pyramid)
113 |
114 | # smoothness_cost = self.vo.multi_scale_smoothness_cost(inv_depth_pyramid, levels=range(1,5))
115 | # smoothness_cost = self.vo.multi_scale_smoothness_cost(inv_depth0_pyramid, levels=range(1,5))
116 | photometric_cost = self.vo.compute_phtometric_loss(self.vo.ref_frame_pyramid, src_frames_pyramid, ref_inv_depth_pyramid, src_inv_depth_pyramid, rot_mat_batch, trans_batch, levels=[0,1,2,3], use_ssim=use_ssim)
117 | smoothness_cost = self.vo.multi_scale_image_aware_smoothness_cost(inv_depth0_pyramid, frames_pyramid, levels=[2,3], type=self.smooth_term) \
118 | + self.vo.multi_scale_image_aware_smoothness_cost(inv_depth_norm_pyramid, frames_pyramid, levels=[2,3], type=self.smooth_term)
119 |
120 | # photometric_cost0, reproj_cost0, _, _ = self.vo.compute_phtometric_loss(self.vo.ref_frame_pyramid, src_frames_pyramid, ref_inv_depth0_pyramid, src_inv_depth0_pyramid, rot_mat_batch, trans_batch)
121 |
122 |
123 | # cost = photometric_cost + photometric_cost0 + reproj_cost + reproj_cost0 + lambda_S*smoothness_cost
124 | cost = photometric_cost + lambda_S*smoothness_cost
125 | return cost, photometric_cost, smoothness_cost, self.vo.ref_frame_pyramid[0], ref_inv_depth0_pyramid[0]*inv_depth_mean_ten
126 |
127 |
128 | if __name__ == "__main__":
129 | from KITTIdataset import KITTIdataset
130 | from torch.utils.data import DataLoader
131 | from torch import optim
132 | from torch.autograd import Variable
133 |
134 | dataset = KITTIdataset()
135 | dataloader = DataLoader(dataset, batch_size=3,
136 | shuffle=True, num_workers=4, pin_memory=True)
137 | lkvolearner = LKVOLearner(gpu_ids = [0, 1, 2])
138 | def weights_init(m):
139 | classname = m.__class__.__name__
140 | if isinstance(m, torch.nn.Conv2d) or isinstance(m, torch.nn.ConvTranspose2d):
141 | # m.weight.data.normal_(0.0, 0.02)
142 | m.bias.data = torch.zeros(m.bias.data.size())
143 |
144 | lkvolearner.apply(weights_init)
145 | lkvolearner.cuda()
146 |
147 | optimizer = optim.Adam(lkvolearner.parameters(), lr=.0001)
148 | for ii, data in enumerate(dataloader):
149 | t = timer()
150 | optimizer.zero_grad()
151 | frames = Variable(data[0].float().cuda())
152 | # print(data[1])
153 | camparams = Variable(data[1])
154 | a = lkvolearner.forward(frames, camparams)
155 | print(timer()-t)
156 | # print(a)
157 |
--------------------------------------------------------------------------------
/src/networks.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import torch.nn as nn
3 | from torch.nn import init
4 | import functools
5 | from torch.autograd import Variable
6 | import numpy as np
7 |
8 |
9 | DISP_SCALING = 10
10 | MIN_DISP = 0.01
11 |
12 | class ConvBlock(nn.Module):
13 | def __init__(self, input_nc, output_nc, kernel_size):
14 | super(ConvBlock, self).__init__()
15 | p = int(np.floor((kernel_size - 1) / 2))
16 | self.activation_fn = nn.ELU()
17 | self.conv1 = Conv(input_nc, output_nc, kernel_size, 1, p, self.activation_fn)
18 | # self.conv2 = Conv(output_nc, output_nc, kernel_size, 2, p)
19 | self.conv2 = Conv(output_nc, output_nc, kernel_size, 1, p, None)
20 |
21 | def forward(self, input):
22 | x = self.conv1(input)
23 | x = self.conv2(x)
24 | padding = [0, int(np.mod(input.size(-1), 2)), 0, int(np.mod(input.size(-2), 2))]
25 | x_pad = torch.nn.ReplicationPad2d(padding)(x)
26 | return torch.nn.AvgPool2d(kernel_size=2, stride=2, padding=0)(self.activation_fn(x_pad))
27 |
28 |
29 | class UpConv(nn.Module):
30 | def __init__(self, input_nc, output_nc, kernel_size):
31 | super(UpConv, self).__init__()
32 | self.deconv = nn.ConvTranspose2d(in_channels=input_nc,
33 | out_channels=output_nc,
34 | kernel_size=2,
35 | bias=True,
36 | stride=2,
37 | padding=0)
38 | self.activation_fn = nn.ELU()
39 | def forward(self, input):
40 | return self.activation_fn(self.deconv(input))
41 |
42 | class Conv(nn.Module):
43 | def __init__(self, input_nc, output_nc, kernel_size, stride, padding, activation_func=nn.ELU()):
44 | super(Conv, self).__init__()
45 | self.conv = nn.Conv2d(in_channels=input_nc,
46 | out_channels=output_nc,
47 | kernel_size=kernel_size,
48 | stride=stride,
49 | padding=0,
50 | bias=True)
51 | self.activation_fn = activation_func
52 | self.pad_fn = nn.ReplicationPad2d(padding)
53 |
54 | def forward(self, input):
55 | if self.activation_fn == None:
56 | return self.conv(self.pad_fn(input))
57 | else:
58 | return self.activation_fn(self.conv(self.pad_fn(input)))
59 |
60 |
61 | class VggDepthEstimator(nn.Module):
62 | def __init__(self, input_size=None):
63 | super(VggDepthEstimator, self).__init__()
64 | self.conv_layers = nn.ModuleList([ConvBlock(3, 32, 7)])
65 | self.conv_layers.append(ConvBlock(32, 64, 5))
66 | self.conv_layers.append(ConvBlock(64, 128, 3))
67 |
68 | self.conv_layers.append(ConvBlock(128, 256, 3))
69 |
70 | self.conv_layers.append(ConvBlock(256, 512, 3))
71 |
72 |
73 | self.conv_layers.append(ConvBlock(512, 512, 3))
74 |
75 |
76 | self.conv_layers.append(ConvBlock(512, 512, 3))
77 |
78 |
79 | # print(conv_feat_sizes)
80 |
81 | self.upconv_layers = nn.ModuleList([UpConv(512, 512, 3)])
82 | self.iconv_layers = nn.ModuleList([Conv(512*2, 512, 3, 1, 1)])
83 |
84 | self.upconv_layers.append(UpConv(512, 512, 3))
85 | self.iconv_layers.append(Conv(512*2, 512, 3, 1, 1))
86 | self.invdepth_layers = nn.ModuleList([Conv(512, 1, 3, 1, 1, nn.Sigmoid())])
87 |
88 | self.upconv_layers.append(UpConv(512, 256, 3))
89 | self.iconv_layers.append(Conv(256*2, 256, 3, 1, 1))
90 | self.invdepth_layers.append(Conv(256, 1, 3, 1, 1, nn.Sigmoid()))
91 |
92 | self.upconv_layers.append(UpConv(256, 128, 3))
93 | self.iconv_layers.append(Conv(128*2, 128, 3, 1, 1))
94 | self.invdepth_layers.append(Conv(128, 1, 3, 1, 1, nn.Sigmoid()))
95 |
96 | self.upconv_layers.append(UpConv(128, 64, 3))
97 | self.iconv_layers.append(Conv(64*2+1, 64, 3, 1, 1))
98 | self.invdepth_layers.append(Conv(64, 1, 3, 1, 1, nn.Sigmoid()))
99 |
100 | self.upconv_layers.append(UpConv(64, 32, 3))
101 | self.iconv_layers.append(Conv(32*2+1, 32, 3, 1, 1))
102 | self.invdepth_layers.append(Conv(32, 1, 3, 1, 1, nn.Sigmoid()))
103 |
104 | self.upconv_layers.append(UpConv(32, 16, 3))
105 | self.iconv_layers.append(Conv(16+1, 16, 3, 1, 1))
106 | self.invdepth_layers.append(Conv(16, 1, 3, 1, 1, nn.Sigmoid()))
107 | # self.invdepth_layers.append(InvDepth(16))
108 |
109 | def init_weights(self):
110 | def weights_init(m):
111 | classname = m.__class__.__name__
112 | if isinstance(m, torch.nn.Conv2d) or isinstance(m, torch.nn.ConvTranspose2d):
113 | # m.weight.data.normal_(0.0, 0.02)
114 | m.bias.data = torch.zeros(m.bias.data.size())
115 |
116 | self.apply(weights_init)
117 |
118 | def forward(self, input):
119 | conv_feat = self.conv_layers[0].forward(input)
120 | self.conv_feats = [conv_feat]
121 | for i in range(1, len(self.conv_layers)):
122 | conv_feat = self.conv_layers[i].forward(self.conv_feats[i-1])
123 | self.conv_feats.append(conv_feat)
124 |
125 | upconv_feats = []
126 | invdepth_pyramid = []
127 | for i in range(0, len(self.upconv_layers)):
128 | if i==0:
129 | x = self.upconv_layers[i].forward(self.conv_feats[-1])
130 | else:
131 | x = self.upconv_layers[i].forward(upconv_feats[i-1])
132 | if i 3:
141 | x = torch.cat((x, self.conv_feats[-(2+i)], nn.Upsample(scale_factor=2, mode='bilinear')(invdepth_pyramid[-1])), 1)
142 | else:
143 | x = torch.cat((x, self.conv_feats[-(2+i)]), 1)
144 | upconv_feats.append(self.iconv_layers[i].forward(x))
145 | if i>0:
146 | # invdepth_pyramid.append(self.invdepth_layers[i-1].forward(upconv_feats[-1])*DISP_SCALING+MIN_DISP)
147 | invdepth_pyramid.append(self.invdepth_layers[i-1].forward(upconv_feats[-1]))
148 | # invdepth_pyramid.append(self.invdepth_layers[i-1].forward(upconv_feats[-1]))
149 | invdepth_pyramid = invdepth_pyramid[-1::-1]
150 | invdepth_pyramid = invdepth_pyramid[0:5]
151 | # conv_feats_output = conv_feats_output[0:5]
152 | for i in range(len(invdepth_pyramid)):
153 | invdepth_pyramid[i] = invdepth_pyramid[i].squeeze(1)*DISP_SCALING+MIN_DISP
154 | return invdepth_pyramid
155 | # return invdepth_pyramid, invdepth0_pyramid, normalize_convfeat_pyramid(conv_feats_output)
156 |
157 | class PoseNet(nn.Module):
158 | def __init__(self, bundle_size):
159 | super(PoseNet, self).__init__()
160 | self.bundle_size = bundle_size
161 |
162 | model = [nn.Conv2d(bundle_size*3, 16, kernel_size=7, stride=2, padding=3, bias=True),
163 | nn.ReLU(True),
164 | nn.Conv2d(16, 32, kernel_size=5, stride=2, padding=2, bias=True),
165 | nn.ReLU(True),
166 | nn.Conv2d(32, 64, kernel_size=3, stride=2, padding=1, bias=True),
167 | nn.ReLU(True),
168 | nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1, bias=True),
169 | nn.ReLU(True),
170 | nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1, bias=True),
171 | nn.ReLU(True),
172 | nn.Conv2d(256, 256, kernel_size=3, stride=2, padding=1, bias=True),
173 | nn.ReLU(True),
174 | nn.Conv2d(256, 256, kernel_size=3, stride=2, padding=1, bias=True),
175 | nn.ReLU(True),
176 | nn.Conv2d(256, 6*(bundle_size-1), kernel_size=3, stride=2, padding=1, bias=True)
177 | ]
178 |
179 | self.model = nn.Sequential(*model)
180 |
181 | def forward(self, input):
182 | assert(self.bundle_size*3 == input.size(1))
183 | p = self.model.forward(input)
184 | p = p.view(input.size(0), 6*(self.bundle_size-1), -1).mean(2)
185 | return p.view(input.size(0), self.bundle_size-1, 6) * 0.01
186 |
187 |
188 | class PoseExpNet(nn.Module):
189 | def __init__(self, bundle_size):
190 | super(PoseExpNet, self).__init__()
191 | self.bundle_size = bundle_size
192 | self.convlyr1 = nn.Sequential(*[nn.Conv2d(bundle_size*3, 16, kernel_size=7, stride=2, padding=3, bias=True),
193 | nn.ReLU(True)])
194 | self.convlyr2 = nn.Sequential(*[nn.Conv2d(16, 32, kernel_size=5, stride=2, padding=2, bias=True),
195 | nn.ReLU(True)])
196 | self.convlyr3 = nn.Sequential(*[nn.Conv2d(32, 64, kernel_size=3, stride=2, padding=1, bias=True),
197 | nn.ReLU(True)])
198 | self.convlyr4 = nn.Sequential(*[nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1, bias=True),
199 | nn.ReLU(True)])
200 | self.convlyr5 = nn.Sequential(*[nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1, bias=True),
201 | nn.ReLU(True)])
202 |
203 | self.poselyr = nn.Sequential(*[nn.Conv2d(256, 256, kernel_size=3, stride=2, padding=1, bias=True),
204 | nn.ReLU(True),
205 | nn.Conv2d(256, 256, kernel_size=3, stride=2, padding=1, bias=True),
206 | nn.ReLU(True),
207 | nn.Conv2d(256, 6*(bundle_size-1), kernel_size=3, stride=2, padding=1, bias=True)])
208 |
209 | self.uplyr5 = nn.Sequential(*[nn.ConvTranspose2d(in_channels=256,
210 | out_channels=256,
211 | kernel_size=2,
212 | bias=True,
213 | stride=2,
214 | padding=0),
215 | nn.ReLU(True)])
216 | self.uplyr4 = nn.Sequential(*[nn.ConvTranspose2d(in_channels=256,
217 | out_channels=128,
218 | kernel_size=2,
219 | bias=True,
220 | stride=2,
221 | padding=0),
222 | nn.ReLU(True)])
223 | self.uplyr3 = nn.Sequential(*[nn.ConvTranspose2d(in_channels=128,
224 | out_channels=64,
225 | kernel_size=2,
226 | bias=True,
227 | stride=2,
228 | padding=0),
229 | nn.ReLU(True)])
230 | self.uplyr2 = nn.Sequential(*[nn.ConvTranspose2d(in_channels=64,
231 | out_channels=32,
232 | kernel_size=2,
233 | bias=True,
234 | stride=2,
235 | padding=0),
236 | nn.ReLU(True)])
237 | self.uplyr1 = nn.Sequential(*[nn.ConvTranspose2d(in_channels=32,
238 | out_channels=16,
239 | kernel_size=2,
240 | bias=True,
241 | stride=2,
242 | padding=0),
243 | nn.ReLU(True)])
244 | self.explyr4 = nn.Sequential(*[nn.Conv2d(128, bundle_size, kernel_size=3,
245 | stride=1, padding=1, bias=True),
246 | nn.Sigmoid()])
247 | self.explyr3 = nn.Sequential(*[nn.Conv2d(64, bundle_size, kernel_size=3,
248 | stride=1, padding=1, bias=True),
249 | nn.Sigmoid()])
250 | self.explyr2 = nn.Sequential(*[nn.Conv2d(32, bundle_size, kernel_size=3,
251 | stride=1, padding=1, bias=True),
252 | nn.Sigmoid()])
253 | self.explyr1 = nn.Sequential(*[nn.Conv2d(16, bundle_size, kernel_size=3,
254 | stride=1, padding=1, bias=True),
255 | nn.Sigmoid()])
256 |
257 | def forward(self, input):
258 | conv1 = self.convlyr1(input)
259 | conv2 = self.convlyr2(conv1)
260 | conv3 = self.convlyr3(conv2)
261 | conv4 = self.convlyr4(conv3)
262 | conv5 = self.convlyr5(conv4)
263 |
264 | # output pose
265 | p = self.poselyr.forward(conv5)
266 | p = p.view(input.size(0), 6*(self.bundle_size-1), -1).mean(2)
267 | # multiply predicted pose with a small constant
268 | p = p.view(input.size(0), self.bundle_size-1, 6) * 0.01
269 | # predict multi-scale explainable mask
270 | upcnv5 = self.uplyr5(conv5)
271 | upcnv4 = self.uplyr4(upcnv5)
272 | upcnv3 = self.uplyr3(upcnv4)
273 | upcnv2 = self.uplyr2(upcnv3)
274 | upcnv1 = self.uplyr1(upcnv2)
275 |
276 | mask4 = self.explyr4(upcnv4)
277 | mask3 = self.explyr3(upcnv3)
278 | mask2 = self.explyr2(upcnv2)
279 | mask1 = self.explyr1(upcnv1)
280 |
281 | return p, [mask1, mask2, mask3, mask4]
282 |
283 |
284 |
285 | if __name__ == "__main__":
286 | model = PoseExpNet(3).cuda()
287 | x = Variable(torch.randn(1,9,128,416).cuda())
288 | p, masks = model.forward(x)
289 | for i in range(4):
290 | print(masks[i].size())
291 |
292 |
293 | dnet = VggDepthEstimator([128,416]).cuda()
294 | I = Variable(torch.randn(1,3,128,416).cuda())
295 | invdepth_pyramid = dnet.forward(I)
296 | for i in range(len(invdepth_pyramid)):
297 | print(invdepth_pyramid[i].size())
298 |
--------------------------------------------------------------------------------
/src/DirectVOLayer.py:
--------------------------------------------------------------------------------
1 | # class DirectVO():
2 | import torch
3 | import torch.nn as nn
4 | from torch.autograd import Variable
5 | from torch import optim
6 | from torch.nn import AvgPool2d
7 | from ImagePyramid import ImagePyramidLayer
8 | from BilinearSampling import grid_bilinear_sampling
9 | from MatInverse import inv
10 | import os
11 |
12 | import numpy as np
13 |
14 | import matplotlib.pyplot as plt
15 | from mpl_toolkits.mplot3d import Axes3D
16 | import scipy.io as sio
17 | from timeit import default_timer as timer
18 |
19 | IMG_CHAN = 3
20 |
21 | # helper functions
22 |
23 | def meshgrid(x, y):
24 | imW = x.size(0)
25 | imH = y.size(0)
26 | X = x.unsqueeze(0).repeat(imH, 1)
27 | Y = y.unsqueeze(1).repeat(1, imW)
28 | return X, Y
29 |
30 | def inv_rigid_transformation(rot_mat_batch, trans_batch):
31 | inv_rot_mat_batch = rot_mat_batch.transpose(1,2)
32 | inv_trans_batch = -inv_rot_mat_batch.bmm(trans_batch.unsqueeze(-1)).squeeze(-1)
33 | return inv_rot_mat_batch, inv_trans_batch
34 |
35 | class LaplacianLayer(nn.Module):
36 | def __init__(self):
37 | super(LaplacianLayer, self).__init__()
38 | w_nom = torch.FloatTensor([[0, -1, 0], [-1, 4, -1], [0, -1, 0]]).view(1,1,3,3)
39 | w_den = torch.FloatTensor([[0, 1, 0], [1, 4, 1], [0, 1, 0]]).view(1,1,3,3)
40 | self.register_buffer('w_nom', w_nom)
41 | self.register_buffer('w_den', w_den)
42 |
43 | def forward(self, input, do_normalize=True):
44 | assert(input.dim() == 2 or input.dim()==3 or input.dim()==4)
45 | input_size = input.size()
46 | if input.dim()==4:
47 | x = input.view(input_size[0]*input_size[1], 1,
48 | input_size[2], input_size[3])
49 | elif input.dim()==3:
50 | x = input.unsqueeze(1)
51 | else:
52 | x = input.unsqueeze(0).unsqueeze(0)
53 | x_nom = torch.nn.functional.conv2d(input=x,
54 | weight=Variable(self.w_nom),
55 | stride=1,
56 | padding=0)
57 | if do_normalize:
58 | x_den = torch.nn.functional.conv2d(input=x,
59 | weight=Variable(self.w_den),
60 | stride=1,
61 | padding=0)
62 | # x_den = x.std() + 1e-5
63 | x = (x_nom.abs()/x_den)
64 | else:
65 | x = x_nom.abs()
66 | if input.dim() == 4:
67 | return x.view(input_size[0], input_size[1], input_size[2]-2, input_size[3]-2)
68 | elif input.dim() == 3:
69 | return x.squeeze(1)
70 | elif input.dim() == 2:
71 | return x.squeeze(0).squeeze(0)
72 |
73 |
74 |
75 | class GradientLayer(nn.Module):
76 | def __init__(self):
77 | super(GradientLayer, self).__init__()
78 | wx = torch.FloatTensor([-.5, 0, .5]).view(1, 1, 1, 3)
79 | wy = torch.FloatTensor([[-.5], [0], [.5]]).view(1, 1, 3, 1)
80 | self.register_buffer('wx', wx)
81 | self.register_buffer('wy', wy)
82 | self.padx_func = torch.nn.ReplicationPad2d((1,1,0,0))
83 | self.pady_func = torch.nn.ReplicationPad2d((0,0,1,1))
84 |
85 | def forward(self, img):
86 | img_ = img.unsqueeze(1)
87 | img_padx = self.padx_func(img_)
88 | img_dx = torch.nn.functional.conv2d(input=img_padx,
89 | weight=Variable(self.wx),
90 | stride=1,
91 | padding=0).squeeze(1)
92 |
93 | img_pady = self.pady_func(img_)
94 | img_dy = torch.nn.functional.conv2d(input=img_pady,
95 | weight=Variable(self.wy),
96 | stride=1,
97 | padding=0).squeeze(1)
98 |
99 | return img_dx, img_dy
100 |
101 |
102 | class Twist2Mat(nn.Module):
103 | def __init__(self):
104 | super(Twist2Mat, self).__init__()
105 | self.register_buffer('o', torch.zeros(1,1))
106 | self.register_buffer('E', torch.eye(3))
107 |
108 | def cprodmat_batch(self, a_batch):
109 | batch_size, _ = a_batch.size()
110 | o = Variable(self.o).expand(batch_size, 1)
111 | a0 = a_batch[:, 0:1]
112 | a1 = a_batch[:, 1:2]
113 | a2 = a_batch[:, 2:3]
114 | return torch.cat((o, -a2, a1, a2, o, -a0, -a1, a0, o), 1).view(batch_size, 3, 3)
115 |
116 | def forward(self, twist_batch):
117 | batch_size, _ = twist_batch.size()
118 | rot_angle = twist_batch.norm(p=2, dim=1).view(batch_size, 1).clamp(min=1e-5)
119 | rot_axis = twist_batch / rot_angle.expand(batch_size, 3)
120 | A = self.cprodmat_batch(rot_axis)
121 | return Variable(self.E).view(1, 3, 3).expand(batch_size, 3, 3)\
122 | + A*rot_angle.sin().view(batch_size, 1, 1).expand(batch_size, 3, 3)\
123 | + A.bmm(A)*((1-rot_angle.cos()).view(batch_size, 1, 1).expand(batch_size, 3, 3))
124 |
125 | def compute_img_stats(img):
126 | # img_pad = torch.nn.ReplicationPad2d(1)(img)
127 | img_pad = img
128 | mu = AvgPool2d(kernel_size=3, stride=1, padding=0)(img_pad)
129 | sigma = AvgPool2d(kernel_size=3, stride=1, padding=0)(img_pad**2) - mu**2
130 | return mu, sigma
131 |
132 | def compute_img_stats_pyramid(frames_pyramid):
133 | mu_pyramid = []
134 | sigma_pyramid = []
135 | for layer_idx in range(len(frames_pyramid)):
136 | mu, sigma = compute_img_stats(frames_pyramid[layer_idx])
137 | mu_pyramid.append(mu)
138 | sigma_pyramid.append(sigma)
139 | return mu_pyramid, sigma_pyramid
140 |
141 |
142 | def compute_SSIM(img0, mu0, sigma0, img1, mu1, sigma1):
143 | # img0_img1_pad = torch.nn.ReplicationPad2d(1)(img0 * img1)
144 | img0_img1_pad = img0*img1
145 | sigma01 = AvgPool2d(kernel_size=3, stride=1, padding=0)(img0_img1_pad) - mu0*mu1
146 | # C1 = .01 ** 2
147 | # C2 = .03 ** 2
148 | C1 = .001
149 | C2 = .009
150 |
151 | ssim_n = (2*mu0*mu1 + C1) * (2*sigma01 + C2)
152 | ssim_d = (mu0**2 + mu1**2 + C1) * (sigma0 + sigma1 + C2)
153 | ssim = ssim_n / ssim_d
154 | return ((1-ssim)*.5).clamp(0, 1)
155 |
156 |
157 | def compute_photometric_cost(img_diff, mask):
158 | # cost = ((img0.expand_as(img1) - img1) * mask).abs().sum()
159 | k = img_diff.size(1)
160 | batch_size = img_diff.size(0)
161 | mask_ = (mask.view(batch_size, 1, -1) * (1/127.5)).expand_as(img_diff)
162 | # mask_ = (mask.view(batch_size, 1, -1)*(1/127.5)).repeat(1, k, 1)
163 | cost = img_diff.abs() * mask_
164 | return cost
165 |
166 | def compute_photometric_cost_norm(img_diff, mask):
167 | # cost = ((img0.expand_as(img1) - img1) * mask).abs().sum()
168 | # k = img_diff.size(1)
169 | # batch_size = img_diff.size(0)
170 | # mask_ = mask.view(batch_size, 1, -1).expand_as(img_diff)
171 |
172 | cost = img_diff.abs().sum(1) * mask
173 | # cost = img_diff.abs() * mask_
174 | num_in_view = mask.sum(1)
175 | # cost_norm = cost.contiguous().sum() / (num_in_view+1e-10)
176 | cost_norm = cost.sum(1) / (num_in_view+1e-10)
177 | # print(mask.size())
178 | return cost_norm * (1 / 127.5), (num_in_view / mask.size(1)).min()
179 |
180 |
181 | def gradient(input, do_normalize=False):
182 | if input.dim() == 2:
183 | D_ry = input[1:, :]
184 | D_ly = input[:-1, :]
185 | D_rx = input[:, 1:]
186 | D_lx = input[:, :-1]
187 | elif input.dim() == 3:
188 | D_ry = input[:, 1:, :]
189 | D_ly = input[:, :-1, :]
190 | D_rx = input[:, :, 1:]
191 | D_lx = input[:, :, :-1]
192 | elif input.dim() == 4:
193 | D_ry = input[:, :, 1:, :]
194 | D_ly = input[:, :, :-1, :]
195 | D_rx = input[:, :, :, 1:]
196 | D_lx = input[:, :, :, :-1]
197 | # if input.dim() == 2:
198 | # D_dy = input[1:, :] - input[:-1, :]
199 | # D_dx = input[:, 1:] - input[:, :-1]
200 | # elif input.dim() == 3:
201 | # D_dy = input[:, 1:, :] - input[:, :-1, :]
202 | # D_dx = input[:, :, 1:] - input[:, :, :-1]
203 | # elif input.dim() == 4:
204 | # D_dy = input[:, :, 1:, :] - input[:, :, :-1, :]
205 | # D_dx = input[:, :, :, 1:] - input[:, :, :, :-1]
206 | Dx = D_rx - D_lx
207 | Dy = D_ry - D_ly
208 | if do_normalize:
209 | Dx = Dx / (D_rx + D_lx)
210 | Dy = Dy / (D_ry + D_ly)
211 | return Dx, Dy
212 |
213 |
214 |
215 |
216 | class DirectVO(nn.Module):
217 |
218 | def __init__(self, imH=128, imW=416, pyramid_layer_num=5, max_itr_num=20):
219 | super(DirectVO, self).__init__()
220 | self.max_itr_num = max_itr_num
221 | self.imH = imH
222 | self.imW = imW
223 | self.pyramid_layer_num = pyramid_layer_num
224 |
225 | self.twist2mat_batch_func = Twist2Mat()
226 | self.img_gradient_func = GradientLayer()
227 | self.pyramid_func = ImagePyramidLayer(chan=3,
228 | pyramid_layer_num=self.pyramid_layer_num)
229 | self.laplacian_func = LaplacianLayer()
230 |
231 | x_pyramid, y_pyramid = self.pyramid_func.get_coords(self.imH, self.imW)
232 |
233 |
234 | # self.x_pyramid = nn.ParameterList(
235 | # [nn.Parameter(torch.from_numpy(x), False) for x in x_pyramid])
236 | # self.y_pyramid = nn.ParameterList(
237 | # [nn.Parameter(torch.from_numpy(y), False) for y in y_pyramid])
238 |
239 | for i in range(self.pyramid_layer_num):
240 | self.register_buffer('x_'+str(i), torch.from_numpy(x_pyramid[i]).float())
241 | self.register_buffer('y_'+str(i), torch.from_numpy(y_pyramid[i]).float())
242 | self.register_buffer('o', torch.zeros(1,1))
243 | self.register_buffer('E', torch.eye(3))
244 |
245 |
246 | def setCamera(self, cx, cy, fx, fy):
247 | self.camparams = dict(fx=fx, fy=fy, cx=cx, cy=cy)
248 |
249 |
250 | def init(self, ref_frame_pyramid, inv_depth_pyramid):
251 | # ref_frame 3 * H * W
252 | assert(self.pyramid_layer_num == len(inv_depth_pyramid))
253 | self.inv_depth_pyramid = inv_depth_pyramid
254 | # self.ref_frame_pyramid = self.pyramid_func(ref_frame)
255 | self.ref_frame_pyramid = ref_frame_pyramid
256 |
257 | for i in range(self.pyramid_layer_num):
258 | assert(self.ref_frame_pyramid[i].size(-1) == inv_depth_pyramid[i].size(-1))
259 | assert (self.ref_frame_pyramid[i].size(-2) == inv_depth_pyramid[i].size(-2))
260 | self.init_lk_terms()
261 |
262 |
263 |
264 | def init_lk_terms(self):
265 | # self.inv_depth_pyramid, self.x_pyramid, self.y_pyramid = buildImagePyramid(inv_depth, self.pyramid_layer_num)
266 | self.xy_pyramid = []
267 | self.ref_imgrad_x_pyramid = []
268 | self.ref_imgrad_y_pyramid = []
269 | self.invH_pyramid = []
270 | self.dIdp_pyramid = []
271 | self.invH_dIdp_pyramid = []
272 |
273 | for i in range(self.pyramid_layer_num):
274 | _, h, w = self.ref_frame_pyramid[i].size()
275 |
276 | x = (Variable(getattr(self, 'x_'+str(i))) - self.camparams['cx']) / self.camparams['fx']
277 | y = (Variable(getattr(self, 'y_'+str(i))) - self.camparams['cy']) / self.camparams['fy']
278 |
279 | X, Y = meshgrid(x, y)
280 | xy = torch.cat((X.view(1, X.numel()),
281 | Y.view(1, Y.numel())), 0)
282 | self.xy_pyramid.append(xy)
283 |
284 | # compute image gradient
285 | imgrad_x, imgrad_y = self.img_gradient_func(self.ref_frame_pyramid[i])
286 |
287 | self.ref_imgrad_x_pyramid.append(imgrad_x*(self.camparams['fx']/2**i))
288 | self.ref_imgrad_y_pyramid.append(imgrad_y*(self.camparams['fy']/2**i))
289 |
290 | # precompute terms for LK regress
291 | dIdp = self.compute_dIdp(self.ref_imgrad_x_pyramid[i],
292 | self.ref_imgrad_y_pyramid[i],
293 | self.inv_depth_pyramid[i],
294 | self.xy_pyramid[i])
295 | self.dIdp_pyramid.append(dIdp)
296 | invH = inv(dIdp.t().mm(dIdp))
297 | self.invH_pyramid.append(invH)
298 | # self.invH_dIdp_pyramid.append(self.invH_pyramid[-1].mm(dIdp.t()))
299 | self.invH_dIdp_pyramid.append(invH.mm(dIdp.t()))
300 |
301 | def init_xy_pyramid(self, ref_frames_pyramid):
302 | # self.inv_depth_pyramid, self.x_pyramid, self.y_pyramid = buildImagePyramid(inv_depth, self.pyramid_layer_num)
303 | self.xy_pyramid = []
304 | self.ref_imgrad_x_pyramid = []
305 | self.ref_imgrad_y_pyramid = []
306 |
307 | for i in range(self.pyramid_layer_num):
308 | _, h, w = ref_frames_pyramid[i].size()
309 |
310 | x = (Variable(getattr(self, 'x_'+str(i))) - self.camparams['cx']) / self.camparams['fx']
311 | y = (Variable(getattr(self, 'y_'+str(i))) - self.camparams['cy']) / self.camparams['fy']
312 |
313 | X, Y = meshgrid(x, y)
314 | xy = torch.cat((X.view(1, X.numel()),
315 | Y.view(1, Y.numel())), 0)
316 | self.xy_pyramid.append(xy)
317 |
318 |
319 |
320 | def compute_dIdp(self, imgrad_x, imgrad_y, inv_depth, xy):
321 | k, h, w = imgrad_x.size()
322 | _, pt_num = xy.size()
323 | assert(h*w == pt_num)
324 | feat_dim = pt_num*k
325 | x = xy[0, :].view(pt_num, 1)
326 | y = xy[1, :].view(pt_num, 1)
327 | xty = x * y
328 | O = Variable(self.o).expand(pt_num, 1)
329 | inv_depth_ = inv_depth.view(pt_num, 1)
330 | dxdp = torch.cat((-xty, 1 + x ** 2, -y, inv_depth_, O, -inv_depth_.mul(x)), 1)
331 | dydp = torch.cat((-1 - y ** 2, xty, x, O, inv_depth_, -inv_depth_.mul(y)), 1)
332 |
333 | imgrad_x_ = imgrad_x.view(feat_dim, 1).expand(feat_dim, 6)
334 | imgrad_y_ = imgrad_y.view(feat_dim, 1).expand(feat_dim, 6)
335 |
336 | dIdp = imgrad_x_.mul(dxdp.repeat(k, 1)) + \
337 | imgrad_y_.mul(dydp.repeat(k, 1))
338 | return dIdp
339 |
340 |
341 |
342 | def LKregress(self, invH_dIdp, mask, It):
343 | batch_size, pt_num = mask.size()
344 | _, k, _ = It.size()
345 | feat_dim = k*pt_num
346 | invH_dIdp_ = invH_dIdp.view(1, 6, feat_dim).expand(batch_size, 6, feat_dim)
347 | mask_ = mask.view(batch_size, 1, pt_num).expand(batch_size, k, pt_num)
348 | # huber_weights = ((255*.2) / (It.abs()+1e-5)).clamp(max=1)
349 | # huber_weights = Variable(huber_weights.data)
350 | # dp = invH_dIdp_.bmm((mask_* huber_weights * It).view(batch_size, feat_dim, 1))
351 | dp = invH_dIdp_.bmm((mask_ * It).view(batch_size, feat_dim, 1))
352 | return dp.view(batch_size, 6)
353 |
354 | def warp_batch(self, img_batch, level_idx, R_batch, t_batch):
355 | return self.warp_batch_func(img_batch, self.inv_depth_pyramid[level_idx], level_idx, R_batch, t_batch)
356 |
357 |
358 | def warp_batch_func(self, img_batch, inv_depth, level_idx, R_batch, t_batch):
359 | batch_size, k, h, w = img_batch.size()
360 | xy = self.xy_pyramid[level_idx]
361 | _, N = xy.size()
362 | # xyz = R_batch.bmm(torch.cat((xy.view(1, 2, N).expand(batch_size, 2, N), Variable(self.load_to_device(torch.ones(batch_size, 1, N)))), 1)) \
363 | # + t_batch.view(batch_size, 3, 1).expand(batch_size, 3, N) * inv_depth.view(1, 1, N).expand(batch_size, 3, N)
364 | xyz = R_batch[:, :, 0:2].bmm(xy.view(1, 2, N).expand(batch_size, 2, N))\
365 | + R_batch[:, :, 2:3].expand(batch_size, 3, N)\
366 | + t_batch.view(batch_size, 3, 1).expand(batch_size, 3, N) * inv_depth.view(-1, 1, N).expand(batch_size, 3, N)
367 | z = xyz[:, 2:3, :].clamp(min=1e-10)
368 | xy_warp = xyz[:, 0:2, :] / z.expand(batch_size, 2, N)
369 | # u_warp = ((xy_warp[:, 0, :]*self.camparams['fx'] + self.camparams['cx'])/2**level_idx - .5).view(batch_size, N)
370 | # v_warp = ((xy_warp[:, 1, :]*self.camparams['fy'] + self.camparams['cy'])/2**level_idx - .5).view(batch_size, N)
371 | # print(self.x_pyramid[level_idx][0])
372 | u_warp = ((xy_warp[:, 0, :] * self.camparams['fx'] + self.camparams['cx']) - getattr(self, 'x_'+str(level_idx))[0]).view(
373 | batch_size, N) / 2 ** level_idx
374 | v_warp = ((xy_warp[:, 1, :] * self.camparams['fy'] + self.camparams['cy']) - getattr(self, 'y_'+str(level_idx))[0]).view(
375 | batch_size, N) / 2 ** level_idx
376 |
377 | Q, in_view_mask = grid_bilinear_sampling(img_batch, u_warp, v_warp)
378 | return Q, in_view_mask * (z.view_as(in_view_mask)>1e-10).float()
379 |
380 |
381 | def compute_phtometric_loss(self, ref_frames_pyramid, src_frames_pyramid, ref_inv_depth_pyramid, src_inv_depth_pyramid,
382 | rot_mat_batch, trans_batch,
383 | use_ssim=True, levels=None,
384 | ref_expl_mask_pyramid=None,
385 | src_expl_mask_pyramid=None):
386 | bundle_size = rot_mat_batch.size(0)+1
387 | inv_rot_mat_batch, inv_trans_batch = inv_rigid_transformation(rot_mat_batch, trans_batch)
388 | src_pyramid = []
389 | ref_pyramid = []
390 | depth_pyramid = []
391 | if levels is None:
392 | levels = range(self.pyramid_layer_num)
393 |
394 | use_expl_mask = not (ref_expl_mask_pyramid is None \
395 | or src_expl_mask_pyramid is None)
396 | if use_expl_mask:
397 | expl_mask_pyramid = []
398 | for level_idx in levels:
399 | ref_mask = ref_expl_mask_pyramid[level_idx].unsqueeze(0).repeat(bundle_size-1,1,1)
400 | src_mask = src_expl_mask_pyramid[level_idx]
401 | expl_mask_pyramid.append(torch.cat(
402 | (ref_mask, src_mask), 0))
403 |
404 |
405 | # for level_idx in range(len(ref_frames_pyramid)):
406 | for level_idx in levels:
407 | # for level_idx in range(3):
408 | ref_frame = ref_frames_pyramid[level_idx].unsqueeze(0).repeat(bundle_size-1, 1, 1, 1)
409 | src_frame = src_frames_pyramid[level_idx]
410 | ref_depth = ref_inv_depth_pyramid[level_idx].unsqueeze(0).repeat(bundle_size-1, 1, 1)
411 | src_depth = src_inv_depth_pyramid[level_idx]
412 | # print(src_depth.size())
413 | ref_pyramid.append(torch.cat((ref_frame,
414 | src_frame), 0)/127.5)
415 | src_pyramid.append(torch.cat((src_frame,
416 | ref_frame), 0)/127.5)
417 | depth_pyramid.append(torch.cat((ref_depth,
418 | src_depth), 0))
419 |
420 |
421 | rot_mat = torch.cat((rot_mat_batch,
422 | inv_rot_mat_batch) ,0)
423 | trans = torch.cat((trans_batch,
424 | inv_trans_batch), 0)
425 |
426 | loss = 0
427 |
428 | frames_warp_pyramid = []
429 | ref_frame_warp_pyramid = []
430 |
431 | # for level_idx in range(len(ref_pyramid)):
432 | # for level_idx in range(3):
433 | for level_idx in levels:
434 | # print(depth_pyramid[level_idx].size())
435 | _, h, w = depth_pyramid[level_idx].size()
436 | warp_img, in_view_mask = self.warp_batch_func(
437 | src_pyramid[level_idx],
438 | depth_pyramid[level_idx],
439 | level_idx, rot_mat, trans)
440 | warp_img = warp_img.view((bundle_size-1)*2, IMG_CHAN, h, w)
441 | if use_expl_mask:
442 | mask = in_view_mask.view(-1,h,w)*expl_mask_pyramid[level_idx]
443 | else:
444 | mask = in_view_mask
445 | mask_expand = mask.view((bundle_size-1)*2, 1, h, w).expand((bundle_size-1)*2, IMG_CHAN, h, w)
446 | rgb_loss = ((ref_pyramid[level_idx] - warp_img).abs()*mask_expand).mean()
447 | if use_ssim and level_idx<1:
448 | # print("compute ssim loss------")
449 | warp_mu, warp_sigma = compute_img_stats(warp_img)
450 | ref_mu, ref_sigma = compute_img_stats(ref_pyramid[level_idx])
451 | ssim = compute_SSIM(ref_pyramid[level_idx],
452 | ref_mu,
453 | ref_sigma,
454 | warp_img,
455 | warp_mu,
456 | warp_sigma)
457 | ssim_loss = (ssim*mask_expand[:,:,1:-1,1:-1]).mean()
458 | loss += .85*ssim_loss+.15*rgb_loss
459 | else:
460 | loss += rgb_loss
461 |
462 | # frames_warp_pyramid.append(warp_img*127.5)
463 | # ref_frame_warp_pyramid.append(ref_pyramid[level_idx]*127.5)
464 | #
465 | # return loss, frames_warp_pyramid, ref_frame_warp_pyramid
466 | return loss
467 |
468 | def compute_smoothness_cost(self, inv_depth):
469 | x = self.laplacian_func(inv_depth)
470 | return x.mean()
471 |
472 | def compute_image_aware_laplacian_smoothness_cost(self, depth, img):
473 | img_lap = self.laplacian_func(img/255, do_normalize=False)
474 | depth_lap = self.laplacian_func(depth, do_normalize=False)
475 | x = (-img_lap.mean(1)).exp()*(depth_lap)
476 | return x.mean()
477 |
478 | def compute_image_aware_2nd_smoothness_cost(self, depth, img):
479 | img_lap = self.laplacian_func(img/255, do_normalize=False)
480 | depth_grad_x, depth_grad_y = gradient(depth, do_normalize=False)
481 | depth_grad_x2, depth_grad_xy = gradient(depth_grad_x, do_normalize=False)
482 | depth_grad_yx, depth_grad_y2 = gradient(depth_grad_y, do_normalize=False)
483 | return depth_grad_x2.abs().mean() \
484 | + depth_grad_xy.abs().mean() + depth_grad_yx.abs().mean() + depth_grad_y2.abs().mean()
485 |
486 |
487 | def compute_image_aware_1st_smoothness_cost(self, depth, img):
488 | depth_grad_x, depth_grad_y = gradient(depth, do_normalize=False)
489 | img_grad_x, img_grad_y = gradient(img/255, do_normalize=False)
490 | if img.dim() == 3:
491 | weight_x = torch.exp(-img_grad_x.abs().mean(0))
492 | weight_y = torch.exp(-img_grad_y.abs().mean(0))
493 | cost = ((depth_grad_x.abs() * weight_x)[:-1, :] + (depth_grad_y.abs() * weight_y)[:, :-1]).mean()
494 | else:
495 | weight_x = torch.exp(-img_grad_x.abs().mean(1))
496 | weight_y = torch.exp(-img_grad_y.abs().mean(1))
497 | cost = ((depth_grad_x.abs() * weight_x)[:, :-1, :] + (depth_grad_y.abs() * weight_y)[:, :, :-1]).mean()
498 | return cost
499 |
500 |
501 |
502 |
503 | def multi_scale_smoothness_cost(self, inv_depth_pyramid, levels = None):
504 | cost = 0
505 | if levels is None:
506 | levels = range(self.pyramid_layer_num)
507 |
508 | # for level_idx in range(2, self.pyramid_layer_num):
509 | for level_idx in levels:
510 | # for level_idx in range(3,4):
511 | inv_depth = inv_depth_pyramid[level_idx]
512 | if inv_depth.dim() == 4:
513 | inv_depth = inv_depth.squeeze(1)
514 | # cost_this_level = compute_img_aware_smoothness_cost(inv_depth, self.ref_frame_pyramid[level_idx]/255)/(2**level_idx)
515 | cost += self.compute_smoothness_cost(inv_depth)/(2**level_idx)
516 | return cost
517 |
518 | def multi_scale_image_aware_smoothness_cost(self, inv_depth_pyramid, img_pyramid, levels=None, type='lap'):
519 | # for level_idx in range(self.pyramid_layer_num):
520 | cost = 0
521 | if levels is None:
522 | levels = range(self.pyramid_layer_num)
523 | for level_idx in levels:
524 | # print(level_idx)
525 | inv_depth = inv_depth_pyramid[level_idx]
526 | if inv_depth.dim() == 4:
527 | inv_depth = inv_depth.squeeze(1)
528 | # cost += compute_img_aware_smoothness_cost(inv_depth, img_pyramid[level_idx])/(2**level_idx)
529 | if type == 'lap':
530 | c = self.compute_image_aware_laplacian_smoothness_cost(inv_depth, img_pyramid[level_idx])
531 | elif type == '1st':
532 | c = self.compute_image_aware_1st_smoothness_cost(inv_depth, img_pyramid[level_idx])
533 | elif type == '2nd':
534 | c = self.compute_image_aware_2nd_smoothness_cost(inv_depth, img_pyramid[level_idx])
535 | else:
536 | print("%s not implemented!" %(type))
537 | cost += (c / (2**level_idx))
538 |
539 | return cost
540 |
541 |
542 | def update(self, frames_pyramid, max_itr_num=10):
543 | frame_num, k, h, w = frames_pyramid[0].size()
544 | trans_batch = Variable(self.o).expand(frame_num, 3).contiguous()
545 | trans_batch_prev = Variable(self.o).expand(frame_num, 3).contiguous()
546 |
547 | rot_mat_batch = Variable(self.E).unsqueeze(0).expand(frame_num, 3, 3).contiguous()
548 | rot_mat_batch_prev = Variable(self.E).unsqueeze(0).expand(frame_num, 3, 3).contiguous()
549 |
550 | pixel_warp = []
551 | in_view_mask = []
552 |
553 | cur_time = timer()
554 |
555 | for level_idx in range(self.pyramid_layer_num-1, -1, -1):
556 |
557 | max_photometric_cost = self.o.squeeze().expand(frame_num)+10000
558 | # print(level_idx)
559 | for i in range(max_itr_num):
560 | # print(i)
561 | # cur_time = timer()
562 | pixel_warp, in_view_mask = self.warp_batch(frames_pyramid[level_idx], level_idx, rot_mat_batch, trans_batch)
563 | # t_warp += timer()-cur_time
564 |
565 | temporal_grad = pixel_warp - self.ref_frame_pyramid[level_idx].view(3, -1).unsqueeze(0).expand_as(pixel_warp)
566 |
567 | photometric_cost, min_perc_in_view = compute_photometric_cost_norm(temporal_grad.data, in_view_mask.data)
568 | # print(photometric_cost)
569 | # print(max_photometric_cost)
570 | # print(min_perc_in_view)
571 | # print((photometric_cost < max_photometric_cost).max())
572 | if min_perc_in_view < .5:
573 | break
574 |
575 | if (photometric_cost < max_photometric_cost).max()>0:
576 | # print(photometric_cost)
577 | trans_batch_prev = trans_batch
578 |
579 | rot_mat_batch_prev = rot_mat_batch
580 |
581 | dp = self.LKregress(invH_dIdp=self.invH_dIdp_pyramid[level_idx],
582 | mask=in_view_mask,
583 | It=temporal_grad)
584 |
585 | d_rot_mat_batch = self.twist2mat_batch_func(-dp[:, 0:3])
586 | trans_batch_new = d_rot_mat_batch.bmm(trans_batch.view(frame_num, 3, 1)).view(frame_num, 3) - dp[:, 3:6]
587 | rot_mat_batch_new = d_rot_mat_batch.bmm(rot_mat_batch)
588 |
589 | trans_list = []
590 | rot_list = []
591 | for k in range(frame_num):
592 | if photometric_cost[k] < max_photometric_cost[k]:
593 | rot_list.append(rot_mat_batch_new[k:k+1, :, :])
594 | trans_list.append(trans_batch_new[k:k+1, :])
595 | max_photometric_cost[k] = photometric_cost[k]
596 | else:
597 | rot_list.append(rot_mat_batch[k:k+1, :, :])
598 | trans_list.append(trans_batch[k:k+1, :])
599 | rot_mat_batch = torch.cat(rot_list, 0)
600 | trans_batch = torch.cat(trans_list, 0)
601 | # if photometric_cost[k] < max_photometric_cost[k]:
602 | # trans_batch = d_rot_mat_batch.bmm(trans_batch.view(frame_num, 3, 1)).view(frame_num, 3) - dp[:, 3:6]
603 | # rot_mat_batch = d_rot_mat_batch.bmm(rot_mat_batch)
604 | else:
605 | break
606 | rot_mat_batch = rot_mat_batch_prev
607 | trans_batch = trans_batch_prev
608 |
609 | return rot_mat_batch, trans_batch, frames_pyramid
610 |
611 | def update_with_init_pose(self, frames_pyramid, rot_mat_batch, trans_batch, max_itr_num=10):
612 | frame_num, k, h, w = frames_pyramid[0].size()
613 | trans_batch_prev = trans_batch
614 | rot_mat_batch_prev = rot_mat_batch
615 |
616 | pixel_warp = []
617 | in_view_mask = []
618 |
619 | cur_time = timer()
620 |
621 | for level_idx in range(len(frames_pyramid)-1, -1, -1):
622 |
623 | max_photometric_cost = self.o.squeeze().expand(frame_num)+10000
624 | # print(level_idx)
625 | for i in range(max_itr_num):
626 | # print(i)
627 | # cur_time = timer()
628 | pixel_warp, in_view_mask = self.warp_batch(frames_pyramid[level_idx], level_idx, rot_mat_batch, trans_batch)
629 | # t_warp += timer()-cur_time
630 |
631 | temporal_grad = pixel_warp - self.ref_frame_pyramid[level_idx].view(3, -1).unsqueeze(0).expand_as(pixel_warp)
632 |
633 | photometric_cost, min_perc_in_view = compute_photometric_cost_norm(temporal_grad.data, in_view_mask.data)
634 |
635 | if min_perc_in_view < .5:
636 | break
637 |
638 | if (photometric_cost < max_photometric_cost).max()>0:
639 |
640 | trans_batch_prev = trans_batch
641 | rot_mat_batch_prev = rot_mat_batch
642 |
643 | dp = self.LKregress(invH_dIdp=self.invH_dIdp_pyramid[level_idx],
644 | mask=in_view_mask,
645 | It=temporal_grad)
646 |
647 | # d_rot_mat_batch = self.twist2mat_batch_func(-dp[:, 0:3])
648 | d_rot_mat_batch = self.twist2mat_batch_func(dp[:, 0:3]).transpose(1,2)
649 | trans_batch_new = d_rot_mat_batch.bmm(trans_batch.view(frame_num, 3, 1)).view(frame_num, 3) - dp[:, 3:6]
650 | rot_mat_batch_new = d_rot_mat_batch.bmm(rot_mat_batch)
651 |
652 | trans_list = []
653 | rot_list = []
654 | # print(photometric_cost)
655 | for k in range(frame_num):
656 | if photometric_cost[k] < max_photometric_cost[k]:
657 | rot_list.append(rot_mat_batch_new[k:k+1, :, :])
658 | trans_list.append(trans_batch_new[k:k+1, :])
659 | max_photometric_cost[k] = photometric_cost[k]
660 | else:
661 | rot_list.append(rot_mat_batch[k:k+1, :, :])
662 | trans_list.append(trans_batch[k:k+1, :])
663 | rot_mat_batch = torch.cat(rot_list, 0)
664 | trans_batch = torch.cat(trans_list, 0)
665 | else:
666 | break
667 | rot_mat_batch = rot_mat_batch_prev
668 | trans_batch = trans_batch_prev
669 |
670 | return rot_mat_batch, trans_batch
671 |
672 |
673 | def forward(self, ref_frame_pyramid, src_frame_pyramid, ref_inv_depth_pyramid, max_itr_num=10):
674 | self.init(ref_frame_pyramid=ref_frame_pyramid, inv_depth_pyramid=ref_inv_depth_pyramid)
675 | rot_mat_batch, trans_batch, src_frames_pyramid = self.update(src_frame_pyramid, max_itr_num=max_itr_num)
676 | return rot_mat_batch, trans_batch
677 |
--------------------------------------------------------------------------------
/test_files_eigen.txt:
--------------------------------------------------------------------------------
1 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000069.png
2 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000054.png
3 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000042.png
4 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000057.png
5 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000030.png
6 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000027.png
7 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000012.png
8 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000075.png
9 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000036.png
10 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000033.png
11 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000015.png
12 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000072.png
13 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000003.png
14 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000039.png
15 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000009.png
16 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000051.png
17 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000060.png
18 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000021.png
19 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000000.png
20 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000024.png
21 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000045.png
22 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000018.png
23 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000048.png
24 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000006.png
25 | 2011_09_26/2011_09_26_drive_0002_sync/image_02/data/0000000063.png
26 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000000.png
27 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000016.png
28 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000032.png
29 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000048.png
30 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000064.png
31 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000080.png
32 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000096.png
33 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000112.png
34 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000128.png
35 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000144.png
36 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000160.png
37 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000176.png
38 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000196.png
39 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000212.png
40 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000228.png
41 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000244.png
42 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000260.png
43 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000276.png
44 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000292.png
45 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000308.png
46 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000324.png
47 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000340.png
48 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000356.png
49 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000372.png
50 | 2011_09_26/2011_09_26_drive_0009_sync/image_02/data/0000000388.png
51 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000090.png
52 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000050.png
53 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000110.png
54 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000115.png
55 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000060.png
56 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000105.png
57 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000125.png
58 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000020.png
59 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000140.png
60 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000085.png
61 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000070.png
62 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000080.png
63 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000065.png
64 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000095.png
65 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000130.png
66 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000100.png
67 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000010.png
68 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000030.png
69 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000000.png
70 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000135.png
71 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000040.png
72 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000005.png
73 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000120.png
74 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000045.png
75 | 2011_09_26/2011_09_26_drive_0013_sync/image_02/data/0000000035.png
76 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000003.png
77 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000069.png
78 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000057.png
79 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000012.png
80 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000072.png
81 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000018.png
82 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000063.png
83 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000000.png
84 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000084.png
85 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000015.png
86 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000066.png
87 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000006.png
88 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000048.png
89 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000060.png
90 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000009.png
91 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000033.png
92 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000021.png
93 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000075.png
94 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000027.png
95 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000045.png
96 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000078.png
97 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000036.png
98 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000051.png
99 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000054.png
100 | 2011_09_26/2011_09_26_drive_0020_sync/image_02/data/0000000042.png
101 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000018.png
102 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000090.png
103 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000126.png
104 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000378.png
105 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000036.png
106 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000288.png
107 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000198.png
108 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000450.png
109 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000144.png
110 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000072.png
111 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000252.png
112 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000180.png
113 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000432.png
114 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000396.png
115 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000054.png
116 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000468.png
117 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000306.png
118 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000108.png
119 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000162.png
120 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000342.png
121 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000270.png
122 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000414.png
123 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000216.png
124 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000360.png
125 | 2011_09_26/2011_09_26_drive_0023_sync/image_02/data/0000000324.png
126 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000077.png
127 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000035.png
128 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000091.png
129 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000112.png
130 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000007.png
131 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000175.png
132 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000042.png
133 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000098.png
134 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000133.png
135 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000161.png
136 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000014.png
137 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000126.png
138 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000168.png
139 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000070.png
140 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000084.png
141 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000140.png
142 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000049.png
143 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000000.png
144 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000182.png
145 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000147.png
146 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000056.png
147 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000063.png
148 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000021.png
149 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000119.png
150 | 2011_09_26/2011_09_26_drive_0027_sync/image_02/data/0000000028.png
151 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000380.png
152 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000394.png
153 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000324.png
154 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000000.png
155 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000268.png
156 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000366.png
157 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000296.png
158 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000014.png
159 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000028.png
160 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000182.png
161 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000168.png
162 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000196.png
163 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000140.png
164 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000084.png
165 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000056.png
166 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000112.png
167 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000352.png
168 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000126.png
169 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000070.png
170 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000310.png
171 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000154.png
172 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000098.png
173 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000408.png
174 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000042.png
175 | 2011_09_26/2011_09_26_drive_0029_sync/image_02/data/0000000338.png
176 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000000.png
177 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000128.png
178 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000192.png
179 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000032.png
180 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000352.png
181 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000608.png
182 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000224.png
183 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000576.png
184 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000672.png
185 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000064.png
186 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000448.png
187 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000704.png
188 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000640.png
189 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000512.png
190 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000768.png
191 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000160.png
192 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000416.png
193 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000480.png
194 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000800.png
195 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000288.png
196 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000544.png
197 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000096.png
198 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000384.png
199 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000256.png
200 | 2011_09_26/2011_09_26_drive_0036_sync/image_02/data/0000000320.png
201 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000000.png
202 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000005.png
203 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000010.png
204 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000015.png
205 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000020.png
206 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000025.png
207 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000030.png
208 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000035.png
209 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000040.png
210 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000045.png
211 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000050.png
212 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000055.png
213 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000060.png
214 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000065.png
215 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000070.png
216 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000075.png
217 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000080.png
218 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000085.png
219 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000090.png
220 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000095.png
221 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000100.png
222 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000105.png
223 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000110.png
224 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000115.png
225 | 2011_09_26/2011_09_26_drive_0046_sync/image_02/data/0000000120.png
226 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000000.png
227 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000001.png
228 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000002.png
229 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000003.png
230 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000004.png
231 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000005.png
232 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000006.png
233 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000007.png
234 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000008.png
235 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000009.png
236 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000010.png
237 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000011.png
238 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000012.png
239 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000013.png
240 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000014.png
241 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000015.png
242 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000016.png
243 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000017.png
244 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000018.png
245 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000019.png
246 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000020.png
247 | 2011_09_26/2011_09_26_drive_0048_sync/image_02/data/0000000021.png
248 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000046.png
249 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000014.png
250 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000036.png
251 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000028.png
252 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000026.png
253 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000050.png
254 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000040.png
255 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000008.png
256 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000016.png
257 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000044.png
258 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000018.png
259 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000032.png
260 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000042.png
261 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000010.png
262 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000020.png
263 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000048.png
264 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000052.png
265 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000006.png
266 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000030.png
267 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000012.png
268 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000038.png
269 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000000.png
270 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000002.png
271 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000004.png
272 | 2011_09_26/2011_09_26_drive_0052_sync/image_02/data/0000000022.png
273 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000011.png
274 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000033.png
275 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000242.png
276 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000253.png
277 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000286.png
278 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000154.png
279 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000099.png
280 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000220.png
281 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000022.png
282 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000077.png
283 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000187.png
284 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000143.png
285 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000066.png
286 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000176.png
287 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000110.png
288 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000275.png
289 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000264.png
290 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000198.png
291 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000055.png
292 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000088.png
293 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000121.png
294 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000209.png
295 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000165.png
296 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000231.png
297 | 2011_09_26/2011_09_26_drive_0056_sync/image_02/data/0000000044.png
298 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000056.png
299 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000000.png
300 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000344.png
301 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000358.png
302 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000316.png
303 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000238.png
304 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000098.png
305 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000112.png
306 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000028.png
307 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000014.png
308 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000330.png
309 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000154.png
310 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000042.png
311 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000302.png
312 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000182.png
313 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000288.png
314 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000140.png
315 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000274.png
316 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000224.png
317 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000372.png
318 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000196.png
319 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000126.png
320 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000084.png
321 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000210.png
322 | 2011_09_26/2011_09_26_drive_0059_sync/image_02/data/0000000070.png
323 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000528.png
324 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000308.png
325 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000044.png
326 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000352.png
327 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000066.png
328 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000000.png
329 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000506.png
330 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000176.png
331 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000022.png
332 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000242.png
333 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000462.png
334 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000418.png
335 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000110.png
336 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000440.png
337 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000396.png
338 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000154.png
339 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000374.png
340 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000088.png
341 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000286.png
342 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000550.png
343 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000264.png
344 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000220.png
345 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000330.png
346 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000484.png
347 | 2011_09_26/2011_09_26_drive_0064_sync/image_02/data/0000000198.png
348 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000283.png
349 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000361.png
350 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000270.png
351 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000127.png
352 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000205.png
353 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000218.png
354 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000153.png
355 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000335.png
356 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000192.png
357 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000348.png
358 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000101.png
359 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000049.png
360 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000179.png
361 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000140.png
362 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000374.png
363 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000322.png
364 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000309.png
365 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000244.png
366 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000062.png
367 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000257.png
368 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000088.png
369 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000114.png
370 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000075.png
371 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000296.png
372 | 2011_09_26/2011_09_26_drive_0084_sync/image_02/data/0000000231.png
373 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000007.png
374 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000196.png
375 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000439.png
376 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000169.png
377 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000115.png
378 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000034.png
379 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000304.png
380 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000331.png
381 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000277.png
382 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000520.png
383 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000682.png
384 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000628.png
385 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000088.png
386 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000601.png
387 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000574.png
388 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000223.png
389 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000655.png
390 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000358.png
391 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000412.png
392 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000142.png
393 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000385.png
394 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000061.png
395 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000493.png
396 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000466.png
397 | 2011_09_26/2011_09_26_drive_0086_sync/image_02/data/0000000250.png
398 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000000.png
399 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000016.png
400 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000032.png
401 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000048.png
402 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000064.png
403 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000080.png
404 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000096.png
405 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000112.png
406 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000128.png
407 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000144.png
408 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000160.png
409 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000176.png
410 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000192.png
411 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000208.png
412 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000224.png
413 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000240.png
414 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000256.png
415 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000305.png
416 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000321.png
417 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000337.png
418 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000353.png
419 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000369.png
420 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000385.png
421 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000401.png
422 | 2011_09_26/2011_09_26_drive_0093_sync/image_02/data/0000000417.png
423 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000000.png
424 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000019.png
425 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000038.png
426 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000057.png
427 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000076.png
428 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000095.png
429 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000114.png
430 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000133.png
431 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000152.png
432 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000171.png
433 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000190.png
434 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000209.png
435 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000228.png
436 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000247.png
437 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000266.png
438 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000285.png
439 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000304.png
440 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000323.png
441 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000342.png
442 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000361.png
443 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000380.png
444 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000399.png
445 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000418.png
446 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000437.png
447 | 2011_09_26/2011_09_26_drive_0096_sync/image_02/data/0000000456.png
448 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000692.png
449 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000930.png
450 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000760.png
451 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000896.png
452 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000284.png
453 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000148.png
454 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000522.png
455 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000794.png
456 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000624.png
457 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000726.png
458 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000216.png
459 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000318.png
460 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000488.png
461 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000590.png
462 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000454.png
463 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000862.png
464 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000386.png
465 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000352.png
466 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000420.png
467 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000658.png
468 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000828.png
469 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000556.png
470 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000114.png
471 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000182.png
472 | 2011_09_26/2011_09_26_drive_0101_sync/image_02/data/0000000080.png
473 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000015.png
474 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000035.png
475 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000043.png
476 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000051.png
477 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000059.png
478 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000067.png
479 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000075.png
480 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000083.png
481 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000091.png
482 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000099.png
483 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000107.png
484 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000115.png
485 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000123.png
486 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000131.png
487 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000139.png
488 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000147.png
489 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000155.png
490 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000163.png
491 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000171.png
492 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000179.png
493 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000187.png
494 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000195.png
495 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000203.png
496 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000211.png
497 | 2011_09_26/2011_09_26_drive_0106_sync/image_02/data/0000000219.png
498 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000312.png
499 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000494.png
500 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000104.png
501 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000130.png
502 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000156.png
503 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000182.png
504 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000598.png
505 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000416.png
506 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000364.png
507 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000026.png
508 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000078.png
509 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000572.png
510 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000468.png
511 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000260.png
512 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000624.png
513 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000234.png
514 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000442.png
515 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000390.png
516 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000546.png
517 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000286.png
518 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000000.png
519 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000338.png
520 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000208.png
521 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000650.png
522 | 2011_09_26/2011_09_26_drive_0117_sync/image_02/data/0000000052.png
523 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000024.png
524 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000021.png
525 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000036.png
526 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000000.png
527 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000051.png
528 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000018.png
529 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000033.png
530 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000090.png
531 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000045.png
532 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000054.png
533 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000012.png
534 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000039.png
535 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000009.png
536 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000003.png
537 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000030.png
538 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000078.png
539 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000060.png
540 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000048.png
541 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000084.png
542 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000081.png
543 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000006.png
544 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000057.png
545 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000072.png
546 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000087.png
547 | 2011_09_28/2011_09_28_drive_0002_sync/image_02/data/0000000063.png
548 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000252.png
549 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000540.png
550 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000001054.png
551 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000036.png
552 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000360.png
553 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000807.png
554 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000879.png
555 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000288.png
556 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000771.png
557 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000000.png
558 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000216.png
559 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000951.png
560 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000324.png
561 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000432.png
562 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000504.png
563 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000576.png
564 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000108.png
565 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000180.png
566 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000072.png
567 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000612.png
568 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000915.png
569 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000735.png
570 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000144.png
571 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000396.png
572 | 2011_09_29/2011_09_29_drive_0071_sync/image_02/data/0000000468.png
573 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000132.png
574 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000011.png
575 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000154.png
576 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000022.png
577 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000242.png
578 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000198.png
579 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000176.png
580 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000231.png
581 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000275.png
582 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000220.png
583 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000088.png
584 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000143.png
585 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000055.png
586 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000033.png
587 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000187.png
588 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000110.png
589 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000044.png
590 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000077.png
591 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000066.png
592 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000000.png
593 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000165.png
594 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000264.png
595 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000253.png
596 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000209.png
597 | 2011_09_30/2011_09_30_drive_0016_sync/image_02/data/0000000121.png
598 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000000107.png
599 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000002247.png
600 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000001391.png
601 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000000535.png
602 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000001819.png
603 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000001177.png
604 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000000428.png
605 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000001926.png
606 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000000749.png
607 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000001284.png
608 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000002140.png
609 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000001605.png
610 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000001498.png
611 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000000642.png
612 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000002740.png
613 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000002419.png
614 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000000856.png
615 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000002526.png
616 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000001712.png
617 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000001070.png
618 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000000000.png
619 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000002033.png
620 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000000214.png
621 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000000963.png
622 | 2011_09_30/2011_09_30_drive_0018_sync/image_02/data/0000002633.png
623 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000533.png
624 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000001040.png
625 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000082.png
626 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000205.png
627 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000835.png
628 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000451.png
629 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000164.png
630 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000794.png
631 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000328.png
632 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000615.png
633 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000917.png
634 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000369.png
635 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000287.png
636 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000123.png
637 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000876.png
638 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000410.png
639 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000492.png
640 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000958.png
641 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000656.png
642 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000000.png
643 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000753.png
644 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000574.png
645 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000001081.png
646 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000041.png
647 | 2011_09_30/2011_09_30_drive_0027_sync/image_02/data/0000000246.png
648 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000002906.png
649 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000002544.png
650 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000000362.png
651 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000004535.png
652 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000000734.png
653 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000001096.png
654 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000004173.png
655 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000000543.png
656 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000001277.png
657 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000004354.png
658 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000001458.png
659 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000001820.png
660 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000003449.png
661 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000003268.png
662 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000000915.png
663 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000002363.png
664 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000002725.png
665 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000000181.png
666 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000001639.png
667 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000003992.png
668 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000003087.png
669 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000002001.png
670 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000003811.png
671 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000003630.png
672 | 2011_10_03/2011_10_03_drive_0027_sync/image_02/data/0000000000.png
673 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000096.png
674 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000800.png
675 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000320.png
676 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000576.png
677 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000000.png
678 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000480.png
679 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000640.png
680 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000032.png
681 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000384.png
682 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000160.png
683 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000704.png
684 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000736.png
685 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000672.png
686 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000064.png
687 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000288.png
688 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000352.png
689 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000512.png
690 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000544.png
691 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000608.png
692 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000128.png
693 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000224.png
694 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000416.png
695 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000192.png
696 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000448.png
697 | 2011_10_03/2011_10_03_drive_0047_sync/image_02/data/0000000768.png
698 |
--------------------------------------------------------------------------------