import os, signal, subprocess import cv2 import numpy as np import json LOG_DIR = "/home/mmbrian/HiWi/etra2016_mohsen/code/recording/data/log.log" FRAMES_DIR = "/home/mmbrian/HiWi/etra2016_mohsen/code/recording/data/frames_012.npy" ARUCO_EXECUTABLE = "/home/mmbrian/temp/aruco-1.3.0/build/utils/aruco_test " ARUCO_SIMPLE_EXECUTABLE = "/home/mmbrian/temp/aruco-1.3.0/build/utils/aruco_simple " RECORDING_VIDEO = "/home/mmbrian/HiWi/pupil_clone/pupil/recordings/2015_09_10/012/world.avi " ## convert videos to avi using: ## avconv -i world.mp4 -c:a copy -c:v copy world.avi CAMERA_MATRIX = "/home/mmbrian/Pictures/chessboard_shots_new/camera.yml " SQUARE_SIZE = "0.029" class MyEncoder(json.JSONEncoder): def default(self, o): if '__dict__' in dir(o): return o.__dict__ else: return str(o) class Marker(object): def __init__(self, _id, p, Rvec, Tvec): ''' p is the array of marker corners in 2D detected in target image ''' self.id = _id self.p = p self.Rvec = Rvec self.Tvec = Tvec def getCenter(self): ''' Returns 3D position of the marker's center in camera coordinate system ''' ret = [] # Constructing 4x4 intrinsic matrix R = cv2.Rodrigues(self.Rvec)[0] for i, row in enumerate(R): ret.append(np.concatenate((row, [self.Tvec[i]]))) ret.append([0, 0, 0, 1]) mat = np.array(ret) # Applying the intrinsic matrix to marker center (wrt marker coordinate system) return mat.dot(np.array([0, 0, 0, 1]))[:-1] # removing the 4th coordinate def getCenterInImage(self, camera_matrix, dist_coeffs): ret = cv2.projectPoints(np.array([(0.0, 0.0, 0.0)]), self.Rvec, self.Tvec, camera_matrix, dist_coeffs) return ret[0][0][0] @classmethod def fromList(cls, data): # np.array([np.array([curr_marker.id]), curr_marker.p, curr_marker.Rvec, curr_marker.Tvec]) return Marker(data[0][0], data[1], data[2], data[3]) # def processFrame(frame_path): # cmd = ARUCO_SIMPLE_EXECUTABLE + frame_path + ' ' + CAMERA_MATRIX + SQUARE_SIZE # p = subprocess.Popen('exec ' + cmd, shell=True, stdout=subprocess.PIPE) # print '########################################################' # print 'Begin Output' # while True: # line = p.stdout.readline() # if line != '': # #the real code does filtering here # print line.rstrip() # else: # break # print 'End Output' # print '########################################################' # # p.terminate() # p.kill() # # os.killpg(p.pid, signal.SIGTERM) def readCameraParams(cam_mat = None): ''' Reads an openCV camera.yml file and returns camera_matrix and distortion_coefficients ''' if not cam_mat: cam_mat = CAMERA_MATRIX data = ''.join(open(cam_mat.strip(), 'r').readlines()).replace('\n', '').lower() try: ind1 = data.index('[', data.index('camera_matrix')) ind2 = data.index(']', ind1) camera_matrix = eval(data[ind1:ind2+1]) camera_matrix = np.array([camera_matrix[:3], camera_matrix[3:6], camera_matrix[6:]]) ind1 = data.index('[', data.index('distortion_coefficients')) ind2 = data.index(']', ind1) dist_coeffs = np.array(eval(data[ind1:ind2+1])) return camera_matrix, dist_coeffs except Exception: print 'Could not load camera parameters' print 'Invalid camera.yml file.' def performMarkerTracking(read_from_log = False, log = False, ret = False, log_dir = None, recording_video = None, frames_dir = None, square_size = None, cam_mat = None): if not log_dir: log_dir = LOG_DIR if not frames_dir: frames_dir = FRAMES_DIR if not recording_video: recording_video = RECORDING_VIDEO if not cam_mat: cam_mat = CAMERA_MATRIX if not square_size: square_size = SQUARE_SIZE square_size = str(square_size) data = [] if read_from_log: if log: print '> Reading data from log file:', log_dir with open(log_dir, 'r') as f: for l in f: if l.strip(): data.append(l) else: if log: print '> Performing marker tracking on file:', recording_video print '> Writing data to log file:', log_dir with open(log_dir, 'w') as f: for l in os.popen(ARUCO_EXECUTABLE + recording_video + cam_mat + square_size): l = l.strip() if '\r' in l: for line in l.split('\r'): if line: f.write(line + "\n") # logging to file data.append(line) else: if l: f.write(l + "\n") # logging to file data.append(l) if log: print '> Parsing marker data...' frame_count = 0 curr_frame = 0 markers = {} frames, frame = [], [] visited_first_frame = False for line in data: line = line.strip().lower() # print # print repr(line) # print if line.startswith('time'): if visited_first_frame: frames.append(frame) visited_first_frame = True frame = [] # if frame: # frames.append(frame) # frame = [] curr_frame=curr_frame+1 nmarkers = int(line[line.index('nmarkers')+9:]) if 'txyz' in line: # This line holds information of a detected marker ind = line.index('=') _id = int(line[:ind]) p = [] for i in xrange(4): pind = ind ind = line.index(' ', pind+1) p.append(line[pind+1:ind]) pind = ind ind = line.index('rxyz', pind) T = line[pind+1+5:ind] R = line[ind+5:] if not _id in markers: markers[_id] = [] curr_marker = Marker(_id, map(lambda pstr: np.array(eval(pstr)), p), np.array(eval('(' + R.strip().replace(' ', ',') + ')')), np.array(eval('(' + T.strip().replace(' ', ',') + ')'))) markers[_id].append(curr_marker) frame.append(np.array([np.array([curr_marker.id]), curr_marker.p, curr_marker.Rvec, curr_marker.Tvec])) # Last frame data frames.append(frame) frames = np.array(frames) if log: print '> Saving marker data for all frames in:', frames_dir np.save(frames_dir, frames) if log: print '> Successfully processed %s frames.' % curr_frame if ret: return markers if __name__ == '__main__': camera_matrix, dist_coeffs = readCameraParams() markers = performMarkerTracking() print '################################################' print len(markers), 'markers detected' for m in markers: # print '################################################' # print markers[m][0].__dict__ # print '################################################' print m, ':', len(markers[m]), 'instances' c = markers[m][0].getCenter() print c * 100, markers[m][0].getCenterInImage(camera_matrix, dist_coeffs) # # TODO: investigate if this is how to get projections of unit vectors # # originating from the camera onto the image plane # # the trick is that we consider a marker with no R and zero T # v = [(0.0, 0.0, 0.0), (1, 0, 0), (0, 1, 0), (0, 0, 1)] # ret = cv2.projectPoints(np.array(v), np.eye(3), np.zeros(3), camera_matrix, dist_coeffs) # p = ret[0] # for i, t in enumerate(v): # print t, 'P->', p[i][0]