Skip to content

Instantly share code, notes, and snippets.

@mattak
Created July 15, 2025 11:00
Show Gist options
  • Save mattak/aaf2665fd3a0720e124df10f90d99d18 to your computer and use it in GitHub Desktop.
Save mattak/aaf2665fd3a0720e124df10f90d99d18 to your computer and use it in GitHub Desktop.
calibrate_fisheye.py
import cv2
import numpy as np
import glob
import os
import argparse
def calibrate_fisheye(folder_path, pattern_size=(9, 6), square_size=1.0, save_path='fisheye_camera_params.npz'):
# 3D座標の準備(Z=0平面)
objp = np.zeros((1, pattern_size[0] * pattern_size[1], 3), np.float32)
objp[0, :, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2)
objp *= square_size
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 path in image_paths:
img = cv2.imread(path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(
gray, pattern_size,
cv2.CALIB_CB_ADAPTIVE_THRESH + cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE
)
if ret:
corners2 = cv2.cornerSubPix(
gray, corners, (3, 3), (-1, -1),
(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.01)
)
imgpoints.append(corners2)
objpoints.append(objp)
print(f"OK: {path}")
else:
print(f"NG: {path}")
if len(objpoints) < 3:
print("十分な有効な画像がありません。最低3枚以上必要です。")
return
N_OK = len(objpoints)
img_shape = gray.shape[::-1]
K = np.zeros((3, 3))
D = np.zeros((4, 1))
rvecs = [np.zeros((1, 1, 3)) for _ in range(N_OK)]
tvecs = [np.zeros((1, 1, 3)) for _ in range(N_OK)]
flags = (
cv2.fisheye.CALIB_RECOMPUTE_EXTRINSIC +
cv2.fisheye.CALIB_CHECK_COND +
cv2.fisheye.CALIB_FIX_SKEW
)
rms, K, D, rvecs, tvecs = cv2.fisheye.calibrate(
objpoints,
imgpoints,
img_shape,
K,
D,
rvecs,
tvecs,
flags,
(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 1e-6)
)
print("\n=== FishEye キャリブレーション結果 ===")
print("RMS 誤差:", rms)
print("Camera Matrix (K):\n", K)
print("Distortion Coefficients (D):\n", D.ravel())
# 保存
np.savez(save_path, K=K, D=D)
print(f"\n保存しました: {save_path}")
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='OpenCV FishEye カメラキャリブレーションスクリプト')
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='fisheye_camera_params.npz', help='出力ファイル名')
args = parser.parse_args()
pattern_size = (args.cols, args.rows)
calibrate_fisheye(
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