Skip to content

Instantly share code, notes, and snippets.

@mattak
Created July 15, 2025 10:59
Show Gist options
  • Save mattak/143aff15cd429b59179dfd691010dfd7 to your computer and use it in GitHub Desktop.
Save mattak/143aff15cd429b59179dfd691010dfd7 to your computer and use it in GitHub Desktop.
calibrate_default.py
import cv2
import numpy as np
import glob
import os
import argparse
def calibrate_from_folder(folder_path, pattern_size=(9, 6), square_size=1.0, save_path='camera_params.npz'):
# 実世界のチェスボード上の交点の3D座標(Z=0の平面上)
objp = np.zeros((pattern_size[0] * pattern_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2)
objp *= square_size # ← ここでmm単位を反映
objpoints = [] # 3D点
imgpoints = [] # 2D点
# 画像ファイルを再帰的に探索
image_paths = glob.glob(os.path.join(folder_path, '**', '*.jpg'), recursive=True)
image_paths += glob.glob(os.path.join(folder_path, '**', '*.png'), recursive=True)
print(f"{len(image_paths)} 枚の画像が見つかりました")
if not image_paths:
print("画像が見つかりませんでした")
return
for img_path in image_paths:
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(gray, pattern_size, None)
if ret:
objpoints.append(objp)
corners2 = cv2.cornerSubPix(
gray, corners, (11, 11), (-1, -1),
criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
)
imgpoints.append(corners2)
print(f"OK: {img_path}")
else:
print(f"NG: {img_path}")
ret, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(
objpoints, imgpoints, gray.shape[::-1], None, None
)
# 再投影誤差の評価
total_error = 0
for i in range(len(objpoints)):
imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], camera_matrix, dist_coeffs)
error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
total_error += error
print("\n=== キャリブレーション結果 ===")
print("Camera Matrix:\n", camera_matrix)
print("Distortion Coefficients:\n", dist_coeffs.ravel())
print("平均再投影誤差: {:.4f}".format(total_error / len(objpoints)))
# 保存
np.savez(save_path, camera_matrix=camera_matrix, dist_coeffs=dist_coeffs)
print(f"\n保存しました: {save_path}")
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='OpenCV カメラキャリブレーションスクリプト')
parser.add_argument('--folder', type=str, required=True, help='チェスボード画像のフォルダパス')
parser.add_argument('--cols', type=int, default=9, help='チェスボードの列(交点数)')
parser.add_argument('--rows', type=int, default=6, help='チェスボードの行(交点数)')
parser.add_argument('--square-size', type=float, default=1.0, help='チェスボード1マスのサイズ(mm単位)')
parser.add_argument('--output', type=str, default='camera_params.npz', help='出力ファイル名')
args = parser.parse_args()
pattern_size = (args.cols, args.rows)
calibrate_from_folder(
folder_path=args.folder,
pattern_size=pattern_size,
square_size=args.square_size,
save_path=args.output
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment