blob: 9a35d9c269b9b4e4d6193a6a9aaf4b2b3c48d03a [file] [log] [blame]
Alex Perry84077a52019-03-06 20:46:42 -08001#!/usr/bin/python
2
3import cv2
4import glob
5import math
6import numpy as np
7import sys
8"""
9Usage:
10 undistort.py [display]
11
12Finds files in /tmp/*.yuyv to compute distortion constants for.
13"""
14
15
16def undist(orig, mtx, dist, newcameramtx, its=1):
17 """
18 This function runs a manual undistort over the entire image to compare to the
19 golden as proof that the algorithm works and the generated constants are correct.
20 """
21 output = np.full(orig.shape, 255, dtype=np.uint8)
22 for i in range(480):
23 for j in range(640):
24 x0 = (i - mtx[1, 2]) / mtx[1, 1]
25 y0 = (j - mtx[0, 2]) / mtx[0, 0]
26 x = x0
27 y = y0
28 for k in range(its):
29 r2 = x * x + y * y
30 coeff = (1 + dist[0, 0] * r2 + dist[0, 1] * math.pow(r2, 2) +
31 dist[0, 4] * math.pow(r2, 3))
32 x = x0 / coeff
33 y = y0 / coeff
34 ip = x * newcameramtx[1, 1] + newcameramtx[1, 2]
35 jp = y * newcameramtx[0, 0] + newcameramtx[0, 2]
36 if ip < 0 or jp < 0 or ip >= 480 or jp >= 640:
37 continue
38 output[int(ip), int(jp)] = orig[i, j]
39 return output
40
41
42def main(argv):
43 # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
44 objp = np.zeros((6 * 9, 3), np.float32)
45 objp[:, :2] = np.mgrid[0:9, 0:6].T.reshape(-1, 2)
46
47 # Arrays to store object points and image points from all the images.
48 objpoints = [] # 3d point in real world space
49 imgpoints = [] # 2d points in image plane.
50
51 images = glob.glob('/tmp/*.yuyv')
52
53 cols = 640
54 rows = 480
55
56 # Iterate through all the available images
57 for fname in images:
58 fd = open(fname, 'rb')
59 f = np.fromfile(fd, np.uint8, cols * rows * 2)
60 # Convert yuyv color space to single channel grey.
61 grey = f[::2]
62 grey = np.reshape(grey, (rows, cols))
63
64 ret, corners = cv2.findChessboardCorners(grey, (9, 6), None)
65 if ret:
66 objpoints.append(objp)
67 imgpoints.append(corners)
68 # Draw the chessboard with corners marked.
69 if len(argv) > 1 and argv[1] == 'display':
70 rgb = cv2.cvtColor(grey, cv2.COLOR_GRAY2RGB)
71 cv2.drawChessboardCorners(rgb, (9, 6), corners, ret)
72 cv2.imshow('', rgb)
73 cv2.waitKey(0)
74 cv2.destroyAllWindows()
75 fd.close()
76
77 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
78 objpoints, imgpoints, grey.shape[::-1], None, None)
79 newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (rows, cols),
80 1, (rows, cols))
81
82 dist[0, 2] = 0
83 dist[0, 3] = 0
84 print("Formatted for Game Config:")
85 print("""distortion {
86 f_x: %f
87 c_x: %f
88 f_y: %f
89 c_y :%f
90 f_x_prime: %f
91 c_x_prime: %f
92 f_y_prime: %f
93 c_y_prime: %f
94 k_1: %f
95 k_2: %f
96 k_3: %f
97 distortion_iterations: 7
98}""" % (
99 # f_x c_x
100 mtx[0][0],
101 mtx[0][2],
102 # f_y c_y
103 mtx[1][1],
104 mtx[1][2],
105 # f_x c_x prime
106 newcameramtx[0][0],
107 newcameramtx[0][2],
108 # f_y c_y prime
109 newcameramtx[1][1],
110 newcameramtx[1][2],
111 # k_1, k_2, k_3
112 dist[0, 0],
113 dist[0, 1],
114 dist[0, 4]))
115
116 # Draw the original image, open-cv undistort, and our undistort in separate
117 # windows for each available image.
118 if len(argv) > 1 and argv[1] == 'display':
119 for fname in images:
120 fd = open(fname, 'rb')
121 f = np.fromfile(fd, np.uint8, cols * rows * 2)
122 grey_t = f[::2]
123 grey_t = np.reshape(grey_t, (rows, cols))
124 dst_expected = cv2.undistort(grey_t, mtx, dist, None, newcameramtx)
125 dst_actual = undist(grey_t, mtx, dist, newcameramtx, 5)
126 cv2.imshow('orig', grey_t)
127 cv2.imshow('opencv undistort', dst_expected)
128 cv2.imshow('our undistort', dst_actual)
129 cv2.waitKey(0)
130 cv2.destroyAllWindows()
131 fd.close()
132
133
134if __name__ == '__main__':
135 main(sys.argv)