Source code for utils

# -*- coding: utf-8 -*-
import os

import cv2 
import numpy as np
from PIL import Image

import json


# neighbourhood parameters
UP, DOWN, LEFT, RIGHT = 0,1,2,3
DIRECTIONS = [UP, DOWN, LEFT, RIGHT]
AFFINE_DIR = {UP:   np.array([[1, 0, 0], [0, 1,-1]], dtype=np.float32),
              DOWN: np.array([[1, 0, 0], [0, 1, 1]], dtype=np.float32),
              LEFT: np.array([[1, 0,-1], [0, 1, 0]], dtype=np.float32),
              RIGHT:np.array([[1, 0, 1], [0, 1, 0]], dtype=np.float32)}

#------------------------------------------------------------------------
[docs]class Sequence(): """ Attributes ---------- height : int height of the camera (important for intrinsic matrix). width : int width of the camera (important for intrinsic matrix). K : numpy matrix, type float32 Matrix with shape `[3, 3]` representing the *intrinsic matrix* of the camera. Rs : list of numpy matrix, type float32 List of numpy matrices with shape `[3, 3]` representing the *rotations* of the camera during the sequence. Ts : list of numpy matrix, type float32 List of numpy matrices with shape `[1, 3]` representing the *translations* of the camera during the sequence. I : list of numpy arrays, type float32 List of numpy arrays with shape `[h,w,3]`, representing the images in the sequence. It must be true that `end - start = len(I)` D : list of numpy arrays, optional, type uint16 List of numpy arrays with shape `[h,w]`, containing previously estimated depth-maps of the sequence. If this parameter is passed as input then the sequence will use *bundle optimization*. It must be true that `end - start = len(I)`. Parameters ---------- configparams : dict Configuration parameters. This dictionary contains information about necessary files directories, as well as the values for various parameters used by the system. """ def __init__(self, configparams): camera_file = configparams["camera_file"] pictures_dir = configparams["pictures_directory"] pictures_ext = configparams["pictures_file_extension"] depthmap_dir = configparams["depthmaps_directory"] height = configparams["height"] width = configparams["width"] start = configparams["start_frame"] end = configparams["end_frame"] self.depth_levels = configparams["depth_levels"] self.depth_min = np.float32(configparams["depth_min"]) self.depth_max = np.float32(configparams["depth_max"]) self.height = height self.width = width self.start = start self.end = end # setup camera parameters----------------------------------------- Ks, Rs, Ts = self._load_camera_params(camera_file) if len(Rs) < end or len(Ts) < end: raise StandardError() self.K = Ks[0] self.Rs = Rs[start:end] self.Ts = Ts[start:end] orig_width = (self.K[0,2]+0.5)*2 orig_height = (self.K[1,2]+0.5)*2 # necessary if target resultion is different from the one used # to estimate the camera parameters. self.K[0, 0] = self.K[0,0]*width/orig_width self.K[1, 1] = self.K[1,1]*height/orig_height self.K[0, 2] = width/2.0 + 0.5 self.K[1, 2] = height/2.0 + 0.5 #----------------------------------------------------------------- self.I = self._load_pictures(pictures_dir, pictures_ext, start, end) self.D = None if depthmap_dir is None else self._load_depthmaps( depthmap_dir, start, end) def _load_camera_params(self, filename): with open(filename,'r') as f: frame_num = int(f.readline()) f.readline() def read_vector(): vec = f.readline().split() return np.array([float(x) for x in vec], dtype=np.float32) def read_matrix(): r1 = read_vector() r2 = read_vector() r3 = read_vector() return np.matrix([r1,r2,r3], dtype=np.float32) K_sequence = [None]*frame_num R_sequence = [None]*frame_num T_sequence = [None]*frame_num for i in range(frame_num): K_sequence[i] = read_matrix() R_sequence[i] = read_matrix() T_sequence[i] = np.asmatrix(read_vector()) f.readline() f.readline() return K_sequence, R_sequence, T_sequence def _load_pictures(self, directory, file_ext, start, end): I = [] for i in range(start, end): img_name = os.path.join(directory,"img_"+str(i).zfill(4)+file_ext) img = cv2.imread(img_name) if img is None: raise StandardError("Image "+img_name+" not found in picture sequence directory ("+directory+")!") I.append(np.float32(cv2.resize(img, (self.width,self.height)))) return I def _load_depthmaps(self, directory, start, end): D = [] for i in range(start, end): depthmap_name = os.path.join(directory, "depth_"+str(i).zfill(4)+".npy") try: depthmap = np.load(depthmap_name) depthmap = np.array(Image.fromarray(depthmap, mode='F').resize( (self.width,self.height), resample=Image.BILINEAR)) D.append(depthmap) except IOError as e: raise StandardError("Depth-map file "+depthmap_name+" not found in depth sequence directory ("+directory+")!") # TODO check correct format shape height, width, labels return D #--------------------------------------------------------------------------
[docs] def use_bundle(self): """Return if this sequence can be used for *bundle optimization*, that is, if it contains previously estimated depth-maps. Returns ------- bool Whether the sequence can be used with *bundle optimization*. """ return self.D != None
#------------------------------------------------------------------------------
[docs]def parse_configfile(filename): """Parse a configuration file and return a dictionary containing the various parameters used by the system. For a more in detail explanation of the parameters contained in the configuration file, and its format see :ref:`config-file`. Parameters ---------- filename : str or unicode Relative or absolute path to the configuration file. Returns ------- dict Dictionary containing the system parameters. If a parameter-value pair was not in the configuration file then its value is ``None``. """ assert isinstance(filename, basestring) required_keys = { "camera_file":basestring, "pictures_directory":basestring, "output_directory":basestring, "pictures_file_extension":basestring, "height":int, "width":int, "start_frame":int, "end_frame":int, "depth_levels":int, "depth_min": float, "depth_max":float } optional_keys = { "depthmaps_directory":basestring, "sigma_c": float, "sigma_d":float, "eta": float, "w_s": float, "epsilon": float, "window_side": int, } # try to parse the file as a json object try: with open(filename,'r') as fp: jobj = json.load(fp=fp) except FileNotFoundError as e: raise StandardError("File "+str(filename)+"not found!") except IOError as e: raise StandardError("Unable to load file "+str(filename)+"!") # check if jason file contains a json object if type(jobj) != dict : raise StandardError("Configuration file should contain a single JSON object!") # check for correct type for key in required_keys: if key not in jobj: raise StandardError("parameter "+key+" is not in the configuration file JSON object!") elif not isinstance(jobj[key], required_keys[key]): raise StandardError("parameter "+key+" has the wrong type: expected "+str(required_keys[key])+", received "+str(type(jobj[key]))+"!") for key in optional_keys: if key not in jobj: jobj[key] = None elif not isinstance(jobj[key], optional_keys[key]): raise StandardError("parameter "+key+" has the wrong value: expected "+str(optional_keys[key])+", received "+str(type(jobj[key]))+"!") # check if there are unknown parameters in the config. file for key in jobj.keys(): if key not in required_keys and key not in optional_keys: raise StandardError("Unknown parameter "+str(key)+" in the configuration file!") # convert relative paths into absolute paths absdirname = os.path.dirname(os.path.abspath(filename)) for key in ["camera_file","depthmaps_directory","pictures_directory", "output_directory"]: if jobj[key] is not None: jobj[key] = os.path.join(absdirname,jobj[key]) return jobj
############################################################################### def show_image(img, secs=0, close_after=True): cv2.imshow('image', cv2.UMat(img)) cv2.waitKey(secs) if close_after: cv2.destroyAllWindows() def show_depthmap(depth_map, secs=0, close_after=True): depth_map = np.array(depth_map) m = depth_map.min() M = depth_map.max() img = np.uint8((depth_map-m)/(M-m)*255) show_image(img, secs, close_after) def load_image_depth(filename, width, height): import struct with open(filename, "rb") as f: def read_float(): bs = f.read(4) if bs=="": return None else: return struct.unpack('f', bs)[0] I = np.zeros([height, width], dtype=np.float32) h, w = 0, 0 disp = read_float() while disp is not None: I[h,w] = disp w = (w + 1) % width h = h + 1 if w==0 else h disp = read_float() return I ###############################################################################