├── 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 = '%s
' % 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 | --------------------------------------------------------------------------------