-
Notifications
You must be signed in to change notification settings - Fork 2
/
modelcamera.py
executable file
·158 lines (129 loc) · 5.07 KB
/
modelcamera.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/env python
"""Create camera model from chessboard images.
(C) 2018-2022 1024jp
"""
import argparse
import os
import sys
from glob import glob
import cv2
import numpy
from modules.undistortion import Undistorter
from modules.stdout import Style
# consts
SUBPIXEL_OPTIONS = {
'winSize': (11, 11),
'zeroZone': (-1, -1),
'criteria': (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, .001),
}
def main(imgdir_path, out_path, chessboard_size, displays=False):
"""Create camera model from chessboard images and pickle the model.
Arguments:
imgdir_path (str) -- path to the directory containing image files.
out_path (str) -- path for camera model to pickle.
chessboard_size (int, int) -- number of inner corners in the chessboard
"""
# grab a set of chessboard images taken with the camera to calibrate
image_paths = glob(os.path.join(imgdir_path, '*.jpg'))
if not image_paths:
sys.exit("Calibration failed. No images of chessboards were found.")
# detect images
img_points = [] # 2D point in image plane
image_size = None
for image_path in sorted(image_paths):
# load image
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
if not image_size:
image_size = gray.shape[::-1]
# find chessboard in the image
found, corners = cv2.findChessboardCorners(gray, chessboard_size, None)
if found:
# enhance corner accuracy
corners = cv2.cornerSubPix(
image=gray,
corners=corners,
**SUBPIXEL_OPTIONS)
# store result
img_points.append(corners)
# display result to stdout
filename = os.path.basename(image_path)
if found:
mark = Style.OK + '✔' + Style.END
else:
mark = Style.FAIL + '━' + Style.END
print("{} {}".format(mark, filename))
# display detection result
img = cv2.drawChessboardCorners(img, chessboard_size, corners, found)
if displays:
display_size = tuple([int(length / 2) for length in image_size])
img = cv2.resize(img, display_size)
cv2.imshow('Chessboard', img)
cv2.waitKey(0) # wait for key press
# destroy any open CV windows
if displays:
cv2.destroyAllWindows()
# exit on failures
if not img_points:
sys.exit("Calibration failed. No chessboards were detected.")
# theoretical 3D object points for the chessboard that will come out like:
# (0, 0, 0), (1, 0, 0), ...,
# (chessboard_size[0]-1, chessboard_size[1]-1, 0)
objp = numpy.zeros((chessboard_size[0]*chessboard_size[1], 3),
numpy.float32)
objp[:, :2] = numpy.mgrid[0:chessboard_size[0],
0:chessboard_size[1]].T.reshape(-1, 2)
obj_points = [objp] * len(img_points)
# create calibration model
_, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(
objectPoints=obj_points,
imagePoints=img_points,
imageSize=image_size,
cameraMatrix=None,
distCoeffs=None)
# pickle
camera = Undistorter(camera_matrix, dist_coeffs, rvecs, tvecs, image_size)
camera.save(out_path)
# display result to stdout
print("Found {} chessboards in total {} images.".format(
Style.BOLD + str(len(img_points)) + Style.END,
Style.BOLD + str(len(image_paths)) + Style.END
))
def parse_args():
"""Parse command-line arguments.
Returns:
args (Namespace) -- namespace object contains parsed arguments
"""
parser = argparse.ArgumentParser(
description='Create camera model from chessboard images.')
# argument
parser.add_argument('imgdir_path',
type=str,
metavar='DIR_PATH',
help="path to the directory containing image files"
)
parser.add_argument('out_file',
type=argparse.FileType('wb'),
metavar='FILE',
help="path for camera model to pickle"
)
# optional arguments
options = parser.add_argument_group('chessboard options')
options.add_argument('-c', '--corners',
type=int,
nargs=2,
default=(6, 9),
metavar=('LOW', 'COL'),
help=("number of inner corners in chessboard"
" (default: %(default)s)")
)
options.add_argument('-d', '--display',
action='store_true',
default=False,
help=("whether display the processing image"
" (default: %(default)s)")
)
return parser.parse_args()
if __name__ == "__main__":
args = parse_args()
main(args.imgdir_path, args.out_file, args.corners, args.display)