comparison scripts/compute-homography.py @ 614:5e09583275a4

Merged Nicolas/trafficintelligence into default
author Mohamed Gomaa <eng.m.gom3a@gmail.com>
date Fri, 05 Dec 2014 12:13:53 -0500
parents 9c429c7efe89
children aded6c1c2ebd
comparison
equal deleted inserted replaced
598:11f96bd08552 614:5e09583275a4
1 #! /usr/bin/env python
2
3 import sys, argparse
4
5 import matplotlib.pyplot as plt
6 import numpy as np
7 import cv2
8
9 import cvutils
10 import utils
11
12 parser = argparse.ArgumentParser(description='The program computes the homography matrix from at least 4 non-colinear point correspondences inputed in the same order in a video frame and a aerial photo/ground map, or from the list of corresponding points in the two planes.', epilog = '''The point correspondence file contains at least 4 non-colinear point coordinates
13 with the following format:
14 - the first two lines are the x and y coordinates in the projected space (usually world space)
15 - the last two lines are the x and y coordinates in the origin space (usually image space)
16
17 If providing video and world images, with a number of points to input
18 and a ration to convert pixels to world distance unit (eg meters per pixel),
19 the images will be shown in turn and the user should click
20 in the same order the corresponding points in world and image spaces.''', formatter_class=argparse.RawDescriptionHelpFormatter,)
21
22 parser.add_argument('-p', dest = 'pointCorrespondencesFilename', help = 'name of the text file containing the point correspondences')
23 parser.add_argument('-i', dest = 'videoFrameFilename', help = 'filename of the video frame')
24 parser.add_argument('-w', dest = 'worldFilename', help = 'filename of the aerial photo/ground map')
25 parser.add_argument('-n', dest = 'nPoints', help = 'number of corresponding points to input', default = 4, type = int)
26 parser.add_argument('-u', dest = 'unitsPerPixel', help = 'number of units per pixel', default = 1., type = float)
27 parser.add_argument('--display', dest = 'displayPoints', help = 'display original and projected points on both images', action = 'store_true')
28 parser.add_argument('--intrinsic', dest = 'intrinsicCameraMatrixFilename', help = 'name of the intrinsic camera file')
29 parser.add_argument('--distortion-coefficients', dest = 'distortionCoefficients', help = 'distortion coefficients', nargs = '*', type = float)
30 parser.add_argument('--undistorted-multiplication', dest = 'undistortedImageMultiplication', help = 'undistorted image multiplication', type = float)
31 parser.add_argument('--undistort', dest = 'undistort', help = 'undistort the video (because features have been extracted that way', action = 'store_true')
32 parser.add_argument('--save', dest = 'saveImages', help = 'save the undistorted video frame (display option must be chosen)', action = 'store_true')
33
34 args = parser.parse_args()
35
36 # TODO process camera intrinsic and extrinsic parameters to obtain image to world homography, taking example from Work/src/python/generate-homography.py script
37 # cameraMat = load(videoFilenamePrefix+'-camera.txt');
38 # T1 = cameraMat[3:6,:].copy();
39 # A = cameraMat[0:3,0:3].copy();
40
41 # # pay attention, rotation may be the transpose
42 # # R = T1[:,0:3].T;
43 # R = T1[:,0:3];
44 # rT = dot(R, T1[:,3]/1000);
45 # T = zeros((3,4),'f');
46 # T[:,0:3] = R[:];
47 # T[:,3] = rT;
48
49 # AT = dot(A,T);
50
51 # nPoints = 4;
52 # worldPoints = cvCreateMat(nPoints, 3, CV_64FC1);
53 # imagePoints = cvCreateMat(nPoints, 3, CV_64FC1);
54
55 # # extract homography from the camera calibration
56 # worldPoints = cvCreateMat(4, 3, CV_64FC1);
57 # imagePoints = cvCreateMat(4, 3, CV_64FC1);
58
59 # worldPoints[0,:] = [[1, 1, 0]];
60 # worldPoints[1,:] = [[1, 2, 0]];
61 # worldPoints[2,:] = [[2, 1, 0]];
62 # worldPoints[3,:] = [[2, 2, 0]];
63
64 # wPoints = [[1,1,2,2],
65 # [1,2,1,2],
66 # [0,0,0,0]];
67 # iPoints = utils.worldToImage(AT, wPoints);
68
69 # for i in range(nPoints):
70 # imagePoints[i,:] = [iPoints[:,i].tolist()];
71
72 # H = cvCreateMat(3, 3, CV_64FC1);
73
74 # cvFindHomography(imagePoints, worldPoints, H);
75
76
77 homography = np.array([])
78 if args.pointCorrespondencesFilename != None:
79 worldPts, videoPts = cvutils.loadPointCorrespondences(args.pointCorrespondencesFilename)
80 homography, mask = cv2.findHomography(videoPts, worldPts) # method=0, ransacReprojThreshold=3
81 elif args.videoFrameFilename != None and args.worldFilename != None:
82 worldImg = plt.imread(args.worldFilename)
83 videoImg = plt.imread(args.videoFrameFilename)
84 if args.undistort:
85 [map1, map2] = cvutils.computeUndistortMaps(videoImg.shape[1], videoImg.shape[0], args.undistortedImageMultiplication, np.loadtxt(args.intrinsicCameraMatrixFilename), args.distortionCoefficients)
86 videoImg = cv2.remap(videoImg, map1, map2, interpolation=cv2.INTER_LINEAR)
87 print('Click on {0} points in the video frame'.format(args.nPoints))
88 plt.figure()
89 plt.imshow(videoImg)
90 videoPts = np.array(plt.ginput(args.nPoints, timeout=3000))
91 print('Click on {0} points in the world image'.format(args.nPoints))
92 plt.figure()
93 plt.imshow(worldImg)
94 worldPts = args.unitsPerPixel*np.array(plt.ginput(args.nPoints, timeout=3000))
95 plt.close('all')
96 homography, mask = cv2.findHomography(videoPts, worldPts)
97 # save the points in file
98 f = open('point-correspondences.txt', 'a')
99 np.savetxt(f, worldPts.T)
100 np.savetxt(f, videoPts.T)
101 f.close()
102
103 if homography.size>0:
104 np.savetxt('homography.txt',homography)
105
106 if args.displayPoints and args.videoFrameFilename != None and args.worldFilename != None and homography.size>0:
107 worldImg = cv2.imread(args.worldFilename)
108 videoImg = cv2.imread(args.videoFrameFilename)
109 if args.undistort:
110 [map1, map2] = cvutils.computeUndistortMaps(videoImg.shape[1], videoImg.shape[0], args.undistortedImageMultiplication, np.loadtxt(args.intrinsicCameraMatrixFilename), args.distortionCoefficients)
111 videoImg = cv2.remap(videoImg, map1, map2, interpolation=cv2.INTER_LINEAR)
112 if args.saveImages:
113 cv2.imwrite(utils.removeExtension(args.videoFrameFilename)+'-undistorted.png', videoImg)
114 invHomography = np.linalg.inv(homography)
115 projectedWorldPts = cvutils.projectArray(invHomography, worldPts.T).T
116 projectedVideoPts = cvutils.projectArray(homography, videoPts.T).T
117 for i in range(worldPts.shape[0]):
118 # world image
119 cv2.circle(worldImg,tuple(np.int32(np.round(worldPts[i]/args.unitsPerPixel))),2,cvutils.cvBlue)
120 cv2.circle(worldImg,tuple(np.int32(np.round(projectedVideoPts[i]/args.unitsPerPixel))),2,cvutils.cvRed)
121 cv2.putText(worldImg, str(i+1), tuple(np.int32(np.round(worldPts[i]/args.unitsPerPixel))+5), cv2.FONT_HERSHEY_PLAIN, 2., cvutils.cvBlue, 2)
122 # video image
123 cv2.circle(videoImg,tuple(np.int32(np.round(videoPts[i]))),2,cvutils.cvBlue)
124 cv2.circle(videoImg,tuple(np.int32(np.round(projectedWorldPts[i]))),2,cvutils.cvRed)
125 cv2.putText(videoImg, str(i+1), tuple(np.int32(np.round(videoPts[i])+5)), cv2.FONT_HERSHEY_PLAIN, 2., cvutils.cvBlue, 2)
126 cv2.imshow('video frame',videoImg)
127 cv2.imshow('world image',worldImg)
128 cv2.waitKey()
129 cv2.destroyAllWindows()