Mercurial > hg > nsaunier > traffic-intelligence
comparison scripts/compute-homography.py @ 1166:7b4d732f82b3
adding an option to use image coordinates in point-correspondence file when undistorting
| author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
|---|---|
| date | Thu, 10 Jun 2021 23:51:42 -0400 |
| parents | 671426ce0f3e |
| children | 6a6a4d5958f7 |
comparison
equal
deleted
inserted
replaced
| 1165:c5863e04d302 | 1166:7b4d732f82b3 |
|---|---|
| 13 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 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 |
| 14 with the following format: | 14 with the following format: |
| 15 - the first two lines are the x and y coordinates in the projected space (usually world space) | 15 - the first two lines are the x and y coordinates in the projected space (usually world space) |
| 16 - the last two lines are the x and y coordinates in the origin space (usually image space) | 16 - the last two lines are the x and y coordinates in the origin space (usually image space) |
| 17 | 17 |
| 18 Image space is in ideal point space (no camera) if undistorting the camera | |
| 19 | |
| 18 If providing video and world images, with a number of points to input | 20 If providing video and world images, with a number of points to input |
| 19 and a ration to convert pixels to world distance unit (eg meters per pixel), | 21 and a ratio to convert pixels to world distance unit (eg meters per pixel), |
| 20 the images will be shown in turn and the user should click | 22 the images will be shown in turn and the user should click |
| 21 in the same order the corresponding points in world and image spaces.''', formatter_class=argparse.RawDescriptionHelpFormatter) | 23 in the same order the corresponding points in world and image spaces.''', formatter_class=argparse.RawDescriptionHelpFormatter) |
| 22 | 24 |
| 23 parser.add_argument('-p', dest = 'pointCorrespondencesFilename', help = 'name of the text file containing the point correspondences') | 25 parser.add_argument('-p', dest = 'pointCorrespondencesFilename', help = 'name of the text file containing the point correspondences') |
| 24 parser.add_argument('--tsai', dest = 'tsaiCameraFilename', help = 'name of the text file containing the camera parameter following the pinhole camera model (Lund format)') # caution, this is Aliaksei's format | 26 parser.add_argument('--tsai', dest = 'tsaiCameraFilename', help = 'name of the text file containing the camera parameter following the pinhole camera model (Lund format)') # caution, this is Aliaksei's format |
| 29 parser.add_argument('-o', dest = 'homographyFilename', help = 'filename of the homography matrix', default = 'homography.txt') | 31 parser.add_argument('-o', dest = 'homographyFilename', help = 'filename of the homography matrix', default = 'homography.txt') |
| 30 parser.add_argument('--display', dest = 'displayPoints', help = 'display original and projected points on both images', action = 'store_true') | 32 parser.add_argument('--display', dest = 'displayPoints', help = 'display original and projected points on both images', action = 'store_true') |
| 31 parser.add_argument('--intrinsic', dest = 'intrinsicCameraMatrixFilename', help = 'name of the intrinsic camera file') | 33 parser.add_argument('--intrinsic', dest = 'intrinsicCameraMatrixFilename', help = 'name of the intrinsic camera file') |
| 32 parser.add_argument('--distortion-coefficients', dest = 'distortionCoefficients', help = 'distortion coefficients', nargs = '*', type = float) | 34 parser.add_argument('--distortion-coefficients', dest = 'distortionCoefficients', help = 'distortion coefficients', nargs = '*', type = float) |
| 33 parser.add_argument('--undistorted-multiplication', dest = 'undistortedImageMultiplication', help = 'undistorted image multiplication', type = float, default = 1.) | 35 parser.add_argument('--undistorted-multiplication', dest = 'undistortedImageMultiplication', help = 'undistorted image multiplication', type = float, default = 1.) |
| 34 parser.add_argument('--undistort', dest = 'undistort', help = 'undistort the video (because features have been extracted that way', action = 'store_true') | 36 parser.add_argument('--undistort', dest = 'undistort', help = 'undistort the video (because features have been extracted that way)', action = 'store_true') |
| 37 parser.add_argument('--correspondences-imagepoints-in-image-space', dest = 'correspondencesImagePointsInImageSpace', help = 'if image points are provided in the actual image space (before undistortion)', action = 'store_true') | |
| 35 parser.add_argument('--save', dest = 'saveImages', help = 'save the undistorted video frame (display option must be chosen)', action = 'store_true') | 38 parser.add_argument('--save', dest = 'saveImages', help = 'save the undistorted video frame (display option must be chosen)', action = 'store_true') |
| 36 | 39 |
| 37 args = parser.parse_args() | 40 args = parser.parse_args() |
| 38 | 41 |
| 39 homography = np.array([]) | 42 homography = np.array([]) |
| 40 if args.pointCorrespondencesFilename is not None: | 43 if args.pointCorrespondencesFilename is not None: |
| 41 worldPts, videoPts = cvutils.loadPointCorrespondences(args.pointCorrespondencesFilename) | 44 worldPts, videoPts = cvutils.loadPointCorrespondences(args.pointCorrespondencesFilename) |
| 45 if args.correspondencesImagePointsInImageSpace: | |
| 46 videoPts = cv2.undistortPoints(videoPts.T, np.loadtxt(args.intrinsicCameraMatrixFilename), np.array(args.distortionCoefficients)).reshape(-1,2) | |
| 42 homography, mask = cv2.findHomography(videoPts, worldPts) # method=0, ransacReprojThreshold=3 | 47 homography, mask = cv2.findHomography(videoPts, worldPts) # method=0, ransacReprojThreshold=3 |
| 43 elif args.tsaiCameraFilename is not None: # hack using PDTV | 48 elif args.tsaiCameraFilename is not None: # hack using PDTV |
| 44 from pdtv import TsaiCamera | 49 from pdtv import TsaiCamera |
| 45 cameraData = storage.loadPinholeCameraModel(args.tsaiCameraFilename) | 50 cameraData = storage.loadPinholeCameraModel(args.tsaiCameraFilename) |
| 46 camera = TsaiCamera(Cx=cameraData['Cx'], Cy=cameraData['Cy'], Sx=cameraData['Sx'], Tx=cameraData['Tx'], Ty=cameraData['Ty'], Tz=cameraData['Tz'], dx=cameraData['dx'], dy=cameraData['dy'], f=cameraData['f'], k=cameraData['k'], r1=cameraData['r1'], r2=cameraData['r2'], r3=cameraData['r3'], r4=cameraData['r4'], r5=cameraData['r5'], r6=cameraData['r6'], r7=cameraData['r7'], r8=cameraData['r8'], r9=cameraData['r9']) | 51 camera = TsaiCamera(Cx=cameraData['Cx'], Cy=cameraData['Cy'], Sx=cameraData['Sx'], Tx=cameraData['Tx'], Ty=cameraData['Ty'], Tz=cameraData['Tz'], dx=cameraData['dx'], dy=cameraData['dy'], f=cameraData['f'], k=cameraData['k'], r1=cameraData['r1'], r2=cameraData['r2'], r3=cameraData['r3'], r4=cameraData['r4'], r5=cameraData['r5'], r6=cameraData['r6'], r7=cameraData['r7'], r8=cameraData['r8'], r9=cameraData['r9']) |
