blob: feeb7c86bad5e8936b9d1687c361693d5233625d [file] [log] [blame]
Austin Schuh085eab92020-11-26 13:54:51 -08001#!/usr/bin/python3
Alex Perry84077a52019-03-06 20:46:42 -08002
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
Ravago Jones5127ccc2022-07-31 16:32:45 -070077 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints,
78 grey.shape[::-1], None,
79 None)
Alex Perry84077a52019-03-06 20:46:42 -080080 newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (rows, cols),
81 1, (rows, cols))
82
83 dist[0, 2] = 0
84 dist[0, 3] = 0
85 print("Formatted for Game Config:")
86 print("""distortion {
87 f_x: %f
88 c_x: %f
89 f_y: %f
90 c_y :%f
91 f_x_prime: %f
92 c_x_prime: %f
93 f_y_prime: %f
94 c_y_prime: %f
95 k_1: %f
96 k_2: %f
97 k_3: %f
98 distortion_iterations: 7
99}""" % (
100 # f_x c_x
101 mtx[0][0],
102 mtx[0][2],
103 # f_y c_y
104 mtx[1][1],
105 mtx[1][2],
106 # f_x c_x prime
107 newcameramtx[0][0],
108 newcameramtx[0][2],
109 # f_y c_y prime
110 newcameramtx[1][1],
111 newcameramtx[1][2],
112 # k_1, k_2, k_3
113 dist[0, 0],
114 dist[0, 1],
115 dist[0, 4]))
116
117 # Draw the original image, open-cv undistort, and our undistort in separate
118 # windows for each available image.
119 if len(argv) > 1 and argv[1] == 'display':
120 for fname in images:
121 fd = open(fname, 'rb')
122 f = np.fromfile(fd, np.uint8, cols * rows * 2)
123 grey_t = f[::2]
124 grey_t = np.reshape(grey_t, (rows, cols))
125 dst_expected = cv2.undistort(grey_t, mtx, dist, None, newcameramtx)
126 dst_actual = undist(grey_t, mtx, dist, newcameramtx, 5)
127 cv2.imshow('orig', grey_t)
128 cv2.imshow('opencv undistort', dst_expected)
129 cv2.imshow('our undistort', dst_actual)
130 cv2.waitKey(0)
131 cv2.destroyAllWindows()
132 fd.close()
133
134
135if __name__ == '__main__':
136 main(sys.argv)